顺序容器是指按照线性顺序存储元素的容器,允许通过位置(索引)来访问元素。C++ STL提供了多种顺序容器,每种容器在内存管理和操作效率上有不同的特点。
特点:
适用场景:
示例代码:
#include
std::vector<int> vec = {1, 2, 3};
vec.push_back(4); // 尾部插入
int val = vec[1]; // 随机访问
特点:
适用场景:
示例代码:
#include
std::deque<int> dq = {1, 2, 3};
dq.push_front(0); // 头部插入
dq.push_back(4); // 尾部插入
int val = dq[2]; // 随机访问
特点:
适用场景:
示例代码:
#include
std::list<int> lst = {1, 2, 3};
lst.insert(++lst.begin(), 4); // 在第二个位置插入
lst.erase(lst.begin()); // 删除头部元素
特点:
适用场景:
示例代码:
#include
std::forward_list<int> flst = {1, 2, 3};
flst.insert_after(flst.begin(), 4); // 在第二个位置插入
flst.erase_after(flst.begin()); // 删除第二个元素
特点:
适用场景:
示例代码:
#include
std::array<int, 3> arr = {1, 2, 3};
int val = arr[1]; // 随机访问
容器 | 特点 | 适用场景 |
---|---|---|
vector |
动态数组,尾部操作高效,支持随机访问 | 需要随机访问或尾部操作 |
deque |
双端队列,头尾操作高效,支持随机访问 | 需要头尾操作或随机访问 |
list |
双向链表,任意位置操作高效,不支持随机访问 | 需要频繁插入/删除 |
forward_list |
单向链表,单向遍历,内存占用更少 | 单向操作且对内存敏感 |
array |
固定大小数组,性能最高,不支持动态调整 | 固定大小且需高性能 |
关联容器是C++标准模板库(STL)中的一类容器,它们通过键(key)来存储和访问元素。关联容器中的元素是按照特定的排序准则自动排序的,这使得查找操作非常高效。
关联容器主要包括以下四种类型:
set
multiset
map
multimap
set
是一个有序的关联容器,它包含唯一键(key)的元素。每个元素在set
中只能出现一次。
特点:
常用操作:
#include
std::set<int> s;
s.insert(10); // 插入元素
s.erase(10); // 删除元素
s.find(10); // 查找元素
s.size(); // 返回元素数量
s.empty(); // 判断是否为空
multiset
类似于set
,但允许存储多个值相同的元素。
特点:
常用操作:
#include
std::multiset<int> ms;
ms.insert(10); // 可以插入多个10
ms.count(10); // 返回值为10的元素个数
map
是一个关联数组,存储键值对(key-value pairs),其中键是唯一的。
特点:
常用操作:
#include
std::map<std::string, int> m;
m["apple"] = 5; // 插入或修改元素
m.erase("apple"); // 删除元素
m.find("apple"); // 查找元素
m.size(); // 返回元素数量
multimap
类似于map
,但允许一个键对应多个值。
特点:
常用操作:
#include
std::multimap<std::string, int> mm;
mm.insert({"apple", 5}); // 可以插入多个"apple"键
mm.count("apple"); // 返回键为"apple"的元素个数
特性 | set | multiset | map | multimap |
---|---|---|---|---|
键唯一性 | 是 | 否 | 是 | 否 |
存储内容 | 键 | 键 | 键值对 | 键值对 |
排序 | 按键 | 按键 | 按键 | 按键 |
允许重复 | 否 | 是 | 否 | 是 |
这些关联容器都定义在
和头文件中,使用时需要包含相应的头文件。
无序容器是C++标准模板库(STL)中基于哈希表实现的容器,它们不保证元素的顺序,但提供了快速的查找、插入和删除操作。无序容器包括以下四种类型:
unordered_set
unordered_multiset
unordered_map
unordered_multimap
特点:
常用操作:
insert()
:插入元素erase()
:删除元素find()
:查找元素count()
:统计元素出现次数(0或1)示例:
std::unordered_set<int> us = {1, 2, 3, 4, 5};
us.insert(6);
us.erase(3);
特点:
unordered_set
类似常用操作:
unordered_set
基本相同count()
可能返回大于1的值示例:
std::unordered_multiset<int> ums = {1, 2, 2, 3, 3, 3};
ums.insert(2);
特点:
常用操作:
insert()
或[]
:插入元素erase()
:删除元素find()
:查找元素at()
:访问元素示例:
std::unordered_map<std::string, int> um = {{"apple", 1}, {"banana", 2}};
um["orange"] = 3;
特点:
unordered_map
类似常用操作:
unordered_map
基本相同count()
可能返回大于1的值equal_range()
:获取指定键的所有元素示例:
std::unordered_multimap<std::string, int> umm = {{"apple", 1}, {"apple", 2}};
umm.insert({"banana", 3});
load_factor()
和max_load_factor()
管理bucket_count()
, bucket_size()
等桶相关操作容器适配器是STL中对基础容器进行封装的一类特殊容器,它们基于现有的序列容器(如vector
、deque
或list
)实现特定的数据结构接口。与普通容器不同,适配器限制了部分功能,仅提供符合其设计目的的接口。STL中主要包含以下三种容器适配器:
stack
deque
,也可指定vector
或list
。push()
:向栈顶插入元素。pop()
:移除栈顶元素(无返回值)。top()
:访问栈顶元素(不删除)。empty()
和 size()
:检查状态。queue
deque
,也可指定list
(不可用vector
,因需支持前端删除)。push()
:向队尾插入元素。pop()
:移除队首元素(无返回值)。front()
和 back()
:分别访问队首和队尾元素。priority_queue
vector
,也可指定deque
。push()
:插入元素并自动排序。pop()
:删除优先级最高的元素。top()
:访问堆顶元素(即最高优先级元素)。greater
)修改优先级规则。stack
用vector
可能触发频繁扩容)。stack
无back()
)。// stack 示例
std::stack<int> s;
s.push(10);
s.pop();
// queue 示例
std::queue<int> q;
q.push(20);
q.pop();
// priority_queue 示例
std::priority_queue<int, std::vector<int>, std::greater<int>> pq;
pq.push(5); // 最小元素优先
输入迭代器(Input Iterator)是 C++ STL 中最简单的迭代器类型之一,主要用于从容器中读取数据。它支持单向遍历,即只能向前移动(通过 ++
操作符),并且只能读取元素的值(通过 *
操作符)。
++
操作符向前移动,不能后退或随机访问。*iter
:解引用迭代器,获取当前元素的值。iter->member
:访问当前元素的成员(如果元素是对象)。++iter
或 iter++
:将迭代器移动到下一个元素。iter1 == iter2
或 iter1 != iter2
:比较两个迭代器是否指向同一个位置。输入迭代器通常用于从输入流(如 std::istream
)或某些算法中读取数据。例如,std::istream_iterator
就是一个输入迭代器。
#include
#include
#include
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 使用输入迭代器遍历 vector
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " "; // 读取元素的值
}
return 0;
}
输出迭代器(Output Iterator)是 C++ STL 中的一种迭代器类型,主要用于向容器中写入数据。它支持单向遍历,并且只能用于写入操作,不能用于读取数据。
++
操作),不能后退或随机访问。*iter
):返回一个左值引用,用于写入数据。++iter
或 iter++
):移动到下一个位置。*iter = value
):将值写入迭代器指向的位置。std::copy
、std::transform
等,用于将数据写入容器。std::ostream_iterator
)。#include
#include
#include
int main() {
std::vector<int> vec(5); // 初始化大小为5的vector
auto it = vec.begin(); // 获取输出迭代器(实际是随机访问迭代器,但支持输出操作)
// 使用输出迭代器写入数据
*it = 10; // 写入第一个元素
++it; // 移动到下一个位置
*it = 20; // 写入第二个元素
// 使用算法写入数据(std::fill 使用输出迭代器)
std::fill(vec.begin(), vec.end(), 42);
return 0;
}
前向迭代器(Forward Iterator)是 C++ STL 中的一种迭代器类型,它提供了单向遍历容器元素的能力。它比输入迭代器(Input Iterator)和输出迭代器(Output Iterator)功能更强,但比双向迭代器(Bidirectional Iterator)和随机访问迭代器(Random Access Iterator)功能更弱。
++
运算符),不能向后移动。*iter
获取当前元素的值。iter->member
访问当前元素的成员。++iter
或 iter++
移动到下一个元素。iter1 == iter2
或 iter1 != iter2
判断两个迭代器是否指向同一位置。前向迭代器适用于单向遍历的容器,如 std::forward_list
和某些哈希表的实现(如 std::unordered_set
和 std::unordered_map
)。
#include
#include
int main() {
std::forward_list<int> flist = {1, 2, 3, 4, 5};
// 使用前向迭代器遍历
for (auto it = flist.begin(); it != flist.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
--
操作,因此不能反向遍历。std::reverse
)需要双向迭代器或随机访问迭代器,不能直接用于前向迭代器。双向迭代器(Bidirectional Iterator)是C++标准模板库(STL)中的一种迭代器类别,它扩展了前向迭代器的功能,允许在序列中向前和向后移动。
++
)和递减(--
)操作。*
)以读取或修改元素的值。++
):移动到下一个元素。--
):移动到上一个元素。*
):访问当前元素的值。->
):访问当前元素的成员(如果元素是对象或结构体)。==
、!=
):判断两个迭代器是否指向同一位置。#include
#include
int main() {
std::list<int> lst = {1, 2, 3, 4, 5};
std::list<int>::iterator it = lst.begin();
// 向前移动
++it;
std::cout << *it << std::endl; // 输出: 2
// 向后移动
--it;
std::cout << *it << std::endl; // 输出: 1
return 0;
}
双向迭代器通常用于以下STL容器:
std::list
std::set
std::multiset
std::map
std::multimap
it + n
或it[n]
),这是随机访问迭代器的特性。随机访问迭代器(Random Access Iterator)是 C++ STL 中最强大的迭代器类型之一,它提供了最丰富的操作功能,允许以任意顺序访问容器中的元素。
++
)和向后(--
)移动。+
和 -
运算符直接跳转到任意位置(如 iter + 5
)。iter[n]
)。==
、!=
、<
、>
、<=
、>=
等比较运算符。std::vector
std::deque
std::array
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = vec.begin();
// 随机访问
it = it + 3; // 现在指向第4个元素(4)
int val = it[1]; // 获取下一个元素(5)
// 比较
if (it > vec.begin()) {
// 迭代器位置比较
}
随机访问迭代器是 STL 算法高效实现的关键,如 std::sort()
就需要这种迭代器。
连续迭代器是 C++ STL 中迭代器的一种类型,属于随机访问迭代器的一个特例。它满足随机访问迭代器的所有要求,并额外保证指向的元素在内存中是连续存储的。
&*it
直接获取元素的指针,且指针算术有效。std::vector
std::array
std::string
(C++17 起)int arr[10]
)std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = vec.begin(); // 连续迭代器
// 随机访问
int third = it[2]; // 3
// 指针算术
int* ptr = &*it; // 获取第一个元素的指针
int next = *(ptr + 1); // 2
std::deque
虽然是随机访问迭代器,但不是连续迭代器。连续迭代器的高效性和指针兼容性使其在需要直接内存操作或与 C 接口交互时非常有用。
非修改算法是指那些不会改变容器中元素的值或顺序的算法。它们主要用于查找、计数或遍历容器中的元素。以下是几个常见的非修改算法:
template <class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& value);
[first, last)
中查找第一个等于 value
的元素。last
。std::vector<int> v = {1, 2, 3, 4, 5};
auto it = std::find(v.begin(), v.end(), 3); // 返回指向 3 的迭代器
template <class InputIterator, class T>
typename iterator_traits<InputIterator>::difference_type
count(InputIterator first, InputIterator last, const T& value);
[first, last)
中等于 value
的元素的个数。std::vector<int> v = {1, 2, 2, 3, 2};
int cnt = std::count(v.begin(), v.end(), 2); // 返回 3
template <class InputIterator1, class InputIterator2>
bool equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2);
[first1, last1)
和 [first2, first2 + (last1 - first1))
的元素是否相等。true
;否则返回 false
。std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {1, 2, 3};
bool isEqual = std::equal(v1.begin(), v1.end(), v2.begin()); // 返回 true
template <class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f);
[first, last)
中的每个元素应用函数 f
。f
(可以是可调用对象或函数指针)。std::vector<int> v = {1, 2, 3};
std::for_each(v.begin(), v.end(), [](int x) { std::cout << x << " "; }); // 输出 1 2 3
这些算法都不会修改容器中的元素,适合用于只读操作。
copy
用于将一个范围内的元素复制到另一个位置。
语法:
OutputIt copy(InputIt first, InputIt last, OutputIt d_first);
first
和 last
是源范围的迭代器。d_first
是目标范围的起始迭代器。d_first + (last - first)
)。示例:
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dest(5);
std::copy(src.begin(), src.end(), dest.begin());
// dest 变为 {1, 2, 3, 4, 5}
transform
对范围内的每个元素应用一个操作,并将结果存储到另一个范围。
语法:
OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first, UnaryOp op);
OutputIt transform(InputIt1 first1, InputIt1 last1, InputIt2 first2, OutputIt d_first, BinaryOp op);
[first1, last1)
的每个元素应用 op
,结果存到 d_first
。[first1, last1)
和 first2
开始的对应元素应用 op
,结果存到 d_first
。示例:
std::vector<int> v = {1, 2, 3};
std::vector<int> result(3);
// 一元操作:平方
std::transform(v.begin(), v.end(), result.begin(), [](int x) { return x * x; });
// result 变为 {1, 4, 9}
fill
将一个范围内的所有元素赋为指定值。
语法:
void fill(ForwardIt first, ForwardIt last, const T& value);
first
和 last
是目标范围的迭代器。value
是要赋的值。示例:
std::vector<int> v(5);
std::fill(v.begin(), v.end(), 42);
// v 变为 {42, 42, 42, 42, 42}
swap
交换两个对象的值。
语法:
void swap(T& a, T& b);
a
和 b
是要交换的对象。示例:
int x = 10, y = 20;
std::swap(x, y);
// x = 20, y = 10
注意:
std::vector
),swap
是高效的(仅交换内部指针)。#include
#include
std::vector<int> v = {4, 2, 5, 3, 1};
std::sort(v.begin(), v.end()); // 升序
std::sort(v.begin(), v.end(), std::greater<int>()); // 降序
#include
#include
std::vector<int> v = {4, 2, 5, 3, 1, 2};
std::stable_sort(v.begin(), v.end()); // 保持两个2的相对顺序
#include
#include
std::vector<int> v = {4, 2, 5, 3, 1};
// 部分排序前3个元素
std::partial_sort(v.begin(), v.begin() + 3, v.end());
// 此时前3个元素为1, 2, 3,其余未排序
lower_bound
是 C++ STL 中的一个二分查找算法,用于在已排序的范围内查找第一个不小于给定值的元素的位置。
template <class ForwardIterator, class T>
ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value);
first
和 last
:定义查找范围的迭代器,范围为 [first, last)
。value
:要查找的目标值。value
的元素的迭代器。value
,则返回 last
。#include
#include
#include
int main() {
std::vector<int> v = {1, 2, 4, 4, 5, 6};
auto it = std::lower_bound(v.begin(), v.end(), 4);
if (it != v.end()) {
std::cout << "First element not less than 4 is at position " << (it - v.begin()) << std::endl;
}
return 0;
}
输出:
First element not less than 4 is at position 2
upper_bound
是 C++ STL 中的另一个二分查找算法,用于在已排序的范围内查找第一个大于给定值的元素的位置。
template <class ForwardIterator, class T>
ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, const T& value);
first
和 last
:定义查找范围的迭代器,范围为 [first, last)
。value
:要查找的目标值。value
的元素的迭代器。value
,则返回 last
。#include
#include
#include
int main() {
std::vector<int> v = {1, 2, 4, 4, 5, 6};
auto it = std::upper_bound(v.begin(), v.end(), 4);
if (it != v.end()) {
std::cout << "First element greater than 4 is at position " << (it - v.begin()) << std::endl;
}
return 0;
}
输出:
First element greater than 4 is at position 4
lower_bound
返回的是第一个不小于 value
的元素。upper_bound
返回的是第一个大于 value
的元素。这两个函数通常一起使用来查找某个值在有序范围内的所有出现位置。例如:
auto lower = std::lower_bound(v.begin(), v.end(), 4);
auto upper = std::upper_bound(v.begin(), v.end(), 4);
// 范围 [lower, upper) 包含所有等于 4 的元素
merge
是 C++ STL 中的一个集合算法,用于将两个已排序的序列合并为一个新的有序序列。它不会修改原始的两个输入序列,而是将结果输出到目标容器中。
函数原型:
template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator merge(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2,
OutputIterator result);
参数说明:
first1
, last1
:第一个输入序列的起始和结束迭代器。first2
, last2
:第二个输入序列的起始和结束迭代器。result
:目标容器的起始迭代器,用于存储合并后的结果。示例:
#include
#include
#include
int main() {
std::vector<int> v1 = {1, 3, 5};
std::vector<int> v2 = {2, 4, 6};
std::vector<int> result(v1.size() + v2.size());
std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin());
for (int num : result) {
std::cout << num << " ";
}
// 输出:1 2 3 4 5 6
return 0;
}
set_union
是 C++ STL 中的一个集合算法,用于计算两个有序序列的并集,并将结果输出到目标容器中。结果序列也是有序的,并且不包含重复元素。
函数原型:
template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator set_union(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2,
OutputIterator result);
参数说明:
first1
, last1
:第一个输入序列的起始和结束迭代器。first2
, last2
:第二个输入序列的起始和结束迭代器。result
:目标容器的起始迭代器,用于存储并集结果。示例:
#include
#include
#include
int main() {
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {2, 3, 4};
std::vector<int> result(v1.size() + v2.size());
auto it = std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin());
result.resize(it - result.begin());
for (int num : result) {
std::cout << num << " ";
}
// 输出:1 2 3 4
return 0;
}
includes
是 C++ STL 中的一个集合算法,用于检查一个有序序列是否包含另一个有序序列的所有元素(即是否为子集)。
函数原型:
template <class InputIterator1, class InputIterator2>
bool includes(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2);
参数说明:
first1
, last1
:第一个输入序列的起始和结束迭代器(可能是更大的集合)。first2
, last2
:第二个输入序列的起始和结束迭代器(可能是子集)。返回值:
true
,否则返回 false
。示例:
#include
#include
#include
int main() {
std::vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<int> v2 = {2, 3, 4};
bool result = std::includes(v1.begin(), v1.end(), v2.begin(), v2.end());
std::cout << (result ? "包含" : "不包含"); // 输出:包含
return 0;
}
plus
template <class T> struct plus;
#include
std::plus<int> add;
int result = add(3, 4); // 结果为7
T
,通常用于基本数据类型(如 int
、float
)。operator+
。minus
template <class T> struct minus;
#include
std::minus<int> subtract;
int result = subtract(5, 3); // 结果为2
T
,适用于支持 operator-
的类型。std::transform
)。multiplies
template <class T> struct multiplies;
#include
std::multiplies<int> multiply;
int result = multiply(2, 3); // 结果为6
T
,要求类型支持 operator*
。
头文件中。operator()
调用。std::accumulate
、std::transform
)配合使用。#include
#include
#include
#include
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// 使用 plus 计算总和
int sum = std::accumulate(v.begin(), v.end(), 0, std::plus<int>());
std::cout << "Sum: " << sum << std::endl; // 输出15
// 使用 multiplies 计算乘积
int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
std::cout << "Product: " << product << std::endl; // 输出120
return 0;
}
在 C++ STL 中,less
、greater
和 equal_to
是预定义的函数对象(也称为仿函数),用于比较两个值。它们通常用于算法、容器(如 set
、map
、priority_queue
)或排序函数(如 sort
)中,以定义元素的比较逻辑。
less
a < b
。std::less
是一个模板类,其中 T
是可比较的类型(如 int
、double
、string
等)。#include
std::less<int> compare;
bool result = compare(3, 5); // 返回 true,因为 3 < 5
set
和 map
使用 less
对元素进行升序排序。sort
函数:std::vector<int> v = {5, 2, 8, 1};
std::sort(v.begin(), v.end(), std::less<int>()); // 升序排序
greater
a > b
。std::greater
是 less
的逆操作。#include
std::greater<int> compare;
bool result = compare(5, 3); // 返回 true,因为 5 > 3
std::vector<int> v = {5, 2, 8, 1};
std::sort(v.begin(), v.end(), std::greater<int>()); // 降序排序
priority_queue
实现最大堆:std::priority_queue<int, std::vector<int>, std::greater<int>> pq;
equal_to
a == b
。std::equal_to
用于判断两个值是否相等。#include
std::equal_to<int> compare;
bool result = compare(3, 3); // 返回 true
find_if
或自定义比较逻辑。less
、greater
和 equal_to
是 STL 提供的标准比较函数对象。T
,可以适配不同类型的比较需求。logical_and
和 logical_or
是 C++ STL 提供的两个逻辑函数对象(function objects),用于执行逻辑与(AND)和逻辑或(OR)操作。它们通常用于算法中,作为谓词(predicate)或比较函数。
这两个函数对象定义在
头文件中。
logical_and
a && b
。std::logical_and<bool> func;
bool result = func(a, b);
#include
#include
int main() {
std::logical_and<bool> and_op;
bool a = true;
bool b = false;
std::cout << std::boolalpha << and_op(a, b) << std::endl; // 输出 false
return 0;
}
logical_or
a || b
。std::logical_or<bool> func;
bool result = func(a, b);
#include
#include
int main() {
std::logical_or<bool> or_op;
bool a = true;
bool b = false;
std::cout << std::boolalpha << or_op(a, b) << std::endl; // 输出 true
return 0;
}
std::transform
、std::accumulate
)结合使用,对容器中的元素进行逻辑运算。std::transform
):#include
#include
#include
#include
int main() {
std::vector<bool> v1 = {true, false, true};
std::vector<bool> v2 = {false, false, true};
std::vector<bool> result(v1.size());
std::transform(v1.begin(), v1.end(), v2.begin(), result.begin(), std::logical_and<bool>());
for (bool val : result) {
std::cout << std::boolalpha << val << " "; // 输出 false false true
}
return 0;
}
logical_and
和 logical_or
是模板类,通常用于布尔类型(bool
),但也可以用于其他可转换为布尔值的类型。operator()
,也可以作为参数传递给其他函数或算法。std::bind
std::bind
是一个通用的函数适配器,用于将函数或成员函数绑定到特定的参数或对象上,生成一个新的可调用对象。它允许部分应用参数(即固定某些参数的值),或者重新排列参数的顺序。
基本用法:
#include
#include
void print_sum(int a, int b) {
std::cout << a + b << std::endl;
}
int main() {
auto bound_func = std::bind(print_sum, 10, std::placeholders::_1);
bound_func(20); // 输出 30(10 + 20)
return 0;
}
std::placeholders::_1
是一个占位符,表示调用 bound_func
时传入的第一个参数。绑定成员函数:
struct MyClass {
void print(int x) { std::cout << x << std::endl; }
};
int main() {
MyClass obj;
auto bound_member = std::bind(&MyClass::print, &obj, std::placeholders::_1);
bound_member(42); // 输出 42
return 0;
}
&obj
)作为第一个参数。std::not1
std::not1
是一个一元函数适配器,用于对一个一元谓词(返回 bool
的函数对象)取反。
基本用法:
#include
#include
#include
struct IsOdd {
bool operator()(int x) const { return x % 2 != 0; }
};
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
auto is_even = std::not1(IsOdd());
auto it = std::find_if(v.begin(), v.end(), is_even);
if (it != v.end()) {
std::cout << "First even number: " << *it << std::endl; // 输出 2
}
return 0;
}
std::not1
将 IsOdd
的返回值取反,得到一个新的谓词 is_even
。限制:
argument_type
类型(如 IsOdd
中的 operator()
参数类型)。std::mem_fn
std::mem_fn
是一个函数适配器,用于将成员函数转换为可调用对象,可以绑定到对象或对象指针上。
基本用法:
#include
#include
#include
struct Person {
std::string name;
void print() const { std::cout << name << std::endl; }
};
int main() {
std::vector<Person> people = {{"Alice"}, {"Bob"}, {"Charlie"}};
std::for_each(people.begin(), people.end(), std::mem_fn(&Person::print));
// 输出:
// Alice
// Bob
// Charlie
return 0;
}
std::mem_fn(&Person::print)
将成员函数 print
转换为可调用对象,可以直接用于算法中。支持多态:
struct Base {
virtual void foo() { std::cout << "Base" << std::endl; }
};
struct Derived : Base {
void foo() override { std::cout << "Derived" << std::endl; }
};
int main() {
Derived d;
Base* ptr = &d;
auto call_foo = std::mem_fn(&Base::foo);
call_foo(ptr); // 输出 "Derived"(多态调用)
return 0;
}
std::mem_fn
支持虚函数的动态绑定。std::bind
:通用函数适配器,支持参数绑定和重排。std::not1
:对一元谓词取反。std::mem_fn
:将成员函数转换为可调用对象。标准分配器是C++标准库中用于内存管理的模板类,定义在
头文件中。它封装了内存分配和释放的操作,是STL容器默认使用的内存分配方式。其核心作用是:
T* allocate(size_t n); // 分配未初始化的内存
void deallocate(T* p, size_t n); // 释放已分配的内存
template<typename U, typename... Args>
void construct(U* p, Args&&... args); // 在指定位置构造对象(C++17后弃用)
void destroy(T* p); // 销毁对象但不释放内存(C++17后弃用)
std::allocator<int> alloc;
int* p = alloc.allocate(5); // 分配5个int的空间
// 构造对象
for(int i=0; i<5; ++i)
alloc.construct(p+i, i*10);
// 使用内存...
for(int i=0; i<5; ++i)
std::cout << p[i] << " ";
// 销毁对象
for(int i=0; i<5; ++i)
alloc.destroy(p+i);
alloc.deallocate(p, 5); // 释放内存
construct()
和destroy()
被弃用,建议使用std::allocator_traits
或placement new自定义分配器(Custom Allocator)是 C++ STL 中的一个重要概念,允许用户控制容器(如 std::vector
、std::list
等)的内存分配行为。默认情况下,STL 容器使用 std::allocator
作为内存分配器,但用户可以通过自定义分配器来优化内存管理,例如实现内存池、共享内存或其他特殊需求。
自定义分配器需要满足以下要求:
value_type
、pointer
、const_pointer
等类型别名。allocate()
和 deallocate()
方法,分别用于分配和释放内存。construct()
和 destroy()
方法(C++11 后通常使用 std::allocator_traits
自动生成)。operator==
和 operator!=
,用于判断两个分配器是否可互换。#include
#include
template <typename T>
struct MyAllocator {
using value_type = T;
MyAllocator() = default;
template <typename U>
MyAllocator(const MyAllocator<U>&) {}
T* allocate(std::size_t n) {
return static_cast<T*>(::operator new(n * sizeof(T)));
}
void deallocate(T* p, std::size_t n) {
::operator delete(p);
}
};
// 比较操作
template <typename T, typename U>
bool operator==(const MyAllocator<T>&, const MyAllocator<U>&) {
return true;
}
template <typename T, typename U>
bool operator!=(const MyAllocator<T>&, const MyAllocator<U>&) {
return false;
}
int main() {
std::vector<int, MyAllocator<int>> v; // 使用自定义分配器
v.push_back(42);
return 0;
}
std::allocator_traits
,简化了自定义分配器的实现,只需实现核心功能(如 allocate
和 deallocate
)。自定义分配器是 STL 中一个高级但强大的工具,适合对性能或内存管理有特殊需求的场景。
分配器特性是C++标准库中的一个模板类,定义在
头文件中,用于提供与分配器(Allocator)相关的统一接口。它主要用于提取和操作分配器的各种属性,而不需要直接访问分配器本身的成员。
allocator_traits
提供默认实现。allocator_traits
包含以下常见的成员类型(假设Alloc
是一个分配器类型):
value_type
:分配的元素类型,等价于Alloc::value_type
。pointer
:指向元素的指针类型,等价于Alloc::pointer
(如果存在),否则为value_type*
。const_pointer
:指向常量元素的指针类型,等价于Alloc::const_pointer
(如果存在),否则为const value_type*
。void_pointer
:指向void
的指针类型,等价于Alloc::void_pointer
(如果存在),否则为void*
。const_void_pointer
:指向const void
的指针类型,等价于Alloc::const_void_pointer
(如果存在),否则为const void*
。difference_type
:指针差值的类型,等价于Alloc::difference_type
(如果存在),否则为std::ptrdiff_t
。size_type
:表示大小的类型,等价于Alloc::size_type
(如果存在),否则为std::size_t
。propagate_on_container_copy_assignment
:布尔类型,表示容器在拷贝赋值时是否传播分配器,等价于Alloc::propagate_on_container_copy_assignment
(如果存在),否则为std::false_type
。propagate_on_container_move_assignment
:布尔类型,表示容器在移动赋值时是否传播分配器,等价于Alloc::propagate_on_container_move_assignment
(如果存在),否则为std::false_type
。propagate_on_container_swap
:布尔类型,表示容器在交换时是否传播分配器,等价于Alloc::propagate_on_container_swap
(如果存在),否则为std::false_type
。allocator_traits
提供以下静态成员函数(假设a
是Alloc
类型的实例):
allocate(a, n)
:分配内存,等价于a.allocate(n)
。deallocate(a, p, n)
:释放内存,等价于a.deallocate(p, n)
。construct(a, p, args...)
:在地址p
构造对象,等价于a.construct(p, args...)
(如果存在),否则使用placement new
。destroy(a, p)
:销毁p
指向的对象,等价于a.destroy(p)
(如果存在),否则调用析构函数。max_size(a)
:返回分配器支持的最大分配大小,等价于a.max_size()
(如果存在),否则返回std::numeric_limits::max() / sizeof(value_type)
。select_on_container_copy_construction(a)
:返回拷贝构造容器时应使用的分配器,等价于a.select_on_container_copy_construction()
(如果存在),否则返回a
。#include
#include
int main() {
using Alloc = std::allocator<int>;
using Traits = std::allocator_traits<Alloc>;
Alloc alloc;
int* p = Traits::allocate(alloc, 1); // 分配内存
Traits::construct(alloc, p, 42); // 构造对象
Traits::destroy(alloc, p); // 销毁对象
Traits::deallocate(alloc, p, 1); // 释放内存
return 0;
}
allocator_traits
是C++标准库中用于简化分配器操作的工具,通过提供默认实现和统一接口,使得自定义分配器的编写更加灵活和方便。
对组(pair)是 C++ 标准模板库(STL)中的一个模板类,用于将两个不同类型的值组合成一个单一的对象。它定义在
头文件中。
template <class T1, class T2>
struct pair {
T1 first;
T2 second;
};
pair
包含两个公有成员变量:
first
:存储第一个值,类型为 T1
。second
:存储第二个值,类型为 T2
。pair
提供了多种构造函数:
first
和 second
为默认值。pair();
first
和 second
。pair(const T1& x, const T2& y);
pair
对象初始化。template<class U, class V> pair(const pair<U, V>& p);
创建 pair
对象
pair<int, string> p1(1, "one");
make_pair
函数(简化创建):auto p2 = make_pair(2, "two");
访问成员
.first
和 .second
访问:cout << p1.first << " " << p1.second; // 输出: 1 one
比较操作
pair
支持比较运算符(==
, !=
, <
, <=
, >
, >=
),按字典序比较(先比较 first
,再比较 second
)。map
或 unordered_map
的键值对(map
的元素是 pair
)。#include
#include
#include
using namespace std;
int main() {
pair<int, string> p(1, "apple");
cout << p.first << ": " << p.second << endl; // 输出: 1: apple
auto q = make_pair(2, "banana");
if (p < q) {
cout << "p is less than q" << endl; // 会输出,因为 1 < 2
}
return 0;
}
元组(tuple)是 C++ 标准模板库(STL)中的一个容器,用于存储固定大小的、不同类型的元素。它是一个通用的数据结构,类似于结构体,但不需要预先定义成员名称。元组在
头文件中定义。
int
、string
、double
等。创建元组
使用 std::tuple
模板类创建元组,可以显式指定类型,也可以使用 std::make_tuple
自动推导类型。
#include
#include
std::tuple<int, std::string, double> t1(1, "hello", 3.14);
auto t2 = std::make_tuple(2, "world", 6.28);
访问元素
使用 std::get
访问元组中的元素,index
必须是编译时常量。
int a = std::get<0>(t1); // 获取第一个元素(1)
std::string b = std::get<1>(t1); // 获取第二个元素("hello")
结构化绑定(C++17 引入)
可以使用结构化绑定直接解包元组元素:
auto [x, y, z] = t1; // x=1, y="hello", z=3.14
比较操作
元组支持比较运算符(==
, !=
, <
, >
, <=
, >=
),按字典序逐元素比较。
元组大小
使用 std::tuple_size
获取元组的大小:
constexpr size_t size = std::tuple_size<decltype(t1)>::value; // 3
std::pair
)。#include
#include
#include
int main() {
// 创建元组
auto student = std::make_tuple(101, "Alice", 85.5);
// 访问元素
int id = std::get<0>(student);
std::string name = std::get<1>(student);
double score = std::get<2>(student);
std::cout << "ID: " << id << ", Name: " << name << ", Score: " << score << std::endl;
// 结构化绑定(C++17)
auto [id2, name2, score2] = student;
std::cout << "ID: " << id2 << ", Name: " << name2 << ", Score: " << score2 << std::endl;
return 0;
}
std::pair
但稍逊于结构体,适合轻量级使用。std::tie
或手动 std::get
。类型特性是C++标准库中的一个重要组成部分,位于
头文件中。它提供了一系列模板类和模板函数,用于在编译时查询和操作类型信息。类型特性主要用于模板元编程,帮助开发者在编译期间做出类型相关的决策。
类型查询:检查类型是否具有某些特性。
std::is_integral
:检查T
是否为整数类型。std::is_floating_point
:检查T
是否为浮点类型。std::is_pointer
:检查T
是否为指针类型。类型关系:检查类型之间的关系。
std::is_same
:检查T
和U
是否为同一类型。std::is_base_of
:检查Base
是否为Derived
的基类。类型转换:在编译时转换类型。
std::remove_const
:移除T
的const
限定符。std::add_pointer
:为T
添加指针修饰符。条件选择:根据条件选择类型。
std::conditional
:如果B
为true
,则选择T
,否则选择F
。#include
#include
int main() {
// 检查类型是否为整数
std::cout << std::boolalpha;
std::cout << "int is integral: " << std::is_integral<int>::value << std::endl;
std::cout << "float is integral: " << std::is_integral<float>::value << std::endl;
// 移除const限定符
typedef std::remove_const<const int>::type NonConstInt;
NonConstInt x = 10; // x的类型是int,而不是const int
// 条件选择类型
typedef std::conditional<true, int, float>::type Type1; // Type1是int
typedef std::conditional<false, int, float>::type Type2; // Type2是float
return 0;
}
类型特性是C++模板编程中不可或缺的工具,能够显著提升代码的灵活性和可维护性。
allocator_traits
是 C++ 标准库中的一个模板类,用于提供对分配器(allocator)的统一访问接口。它定义在
头文件中,主要用于封装和扩展分配器的功能,使得标准库容器可以更灵活地使用不同类型的分配器。
allocator_traits
都提供了一套统一的接口来访问分配器的功能。allocator_traits
会提供默认实现。value_type
:分配器分配的元素类型。pointer
:指向分配元素的指针类型。const_pointer
:指向常量元素的指针类型。void_pointer
:指向 void
的指针类型。const_void_pointer
:指向 const void
的指针类型。difference_type
:指针之间的差值类型。size_type
:表示大小的无符号整数类型。allocate
:分配内存。deallocate
:释放内存。construct
:在已分配的内存上构造对象。destroy
:销毁对象但不释放内存。max_size
:返回分配器可以分配的最大大小。#include
#include
int main() {
std::allocator<int> alloc;
std::allocator_traits<std::allocator<int>> traits;
// 分配内存
int* p = traits.allocate(alloc, 1);
// 构造对象
traits.construct(alloc, p, 42);
std::cout << *p << std::endl; // 输出: 42
// 销毁对象
traits.destroy(alloc, p);
// 释放内存
traits.deallocate(alloc, p, 1);
return 0;
}
allocator_traits
主要用于标准库内部实现,普通用户代码通常不需要直接使用它。allocator_traits
来确保与标准库容器的兼容性。通过 allocator_traits
,C++ 标准库能够更灵活地处理不同类型的内存分配器,同时保持代码的一致性和可维护性。
std::exception
是 C++ 标准库中所有异常类的基类,定义在
头文件中。它提供了一种统一的机制来处理程序运行时可能发生的错误或异常情况。
what()
const char*
)。派生类可以重写此函数以提供更具体的错误信息。try {
// 可能抛出异常的代码
} catch (const std::exception& e) {
std::cerr << "Exception caught: " << e.what() << std::endl;
}
虽然你要求不扩展其他概念,但为了完整性,以下是标准库中一些直接或间接继承自 std::exception
的常见异常类(仅列举名称):
std::runtime_error
std::logic_error
std::bad_alloc
(内存分配失败时抛出)可以通过继承 std::exception
来定义自己的异常类:
class MyException : public std::exception {
public:
const char* what() const noexcept override {
return "Custom exception occurred";
}
};
noexcept
修饰符可以标记函数是否可能抛出异常(C++11 引入)。std::terminate
)。通用数值算法是C++标准模板库(STL)中的一组算法,主要用于对数值序列进行操作和计算。这些算法定义在
头文件中,通常与容器(如 vector
、array
等)一起使用。以下是常见的通用数值算法:
std::accumulate
T accumulate(InputIt first, InputIt last, T init);
T accumulate(InputIt first, InputIt last, T init, BinaryOperation op);
first
和 last
:输入序列的迭代器范围。init
:初始值。op
(可选):二元操作函数(如乘法、减法等)。std::vector<int> nums = {1, 2, 3, 4};
int sum = std::accumulate(nums.begin(), nums.end(), 0); // 输出 10
int product = std::accumulate(nums.begin(), nums.end(), 1, std::multiplies<int>()); // 输出 24
std::inner_product
T inner_product(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init);
T inner_product(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init, BinaryOperation1 op1, BinaryOperation2 op2);
first1
和 last1
:第一个序列的迭代器范围。first2
:第二个序列的起始迭代器(长度需匹配第一个序列)。init
:初始值。op1
(可选):替换加法的二元操作。op2
(可选):替换乘法的二元操作。std::vector<int> a = {1, 2, 3};
std::vector<int> b = {4, 5, 6};
int dot = std::inner_product(a.begin(), a.end(), b.begin(), 0); // 输出 1*4 + 2*5 + 3*6 = 32
std::partial_sum
OutputIt partial_sum(InputIt first, InputIt last, OutputIt d_first);
OutputIt partial_sum(InputIt first, InputIt last, OutputIt d_first, BinaryOperation op);
first
和 last
:输入序列的迭代器范围。d_first
:输出序列的起始迭代器。op
(可选):自定义二元操作(默认为加法)。std::vector<int> nums = {1, 2, 3, 4};
std::vector<int> result(4);
std::partial_sum(nums.begin(), nums.end(), result.begin()); // 输出 {1, 3, 6, 10}
std::adjacent_difference
OutputIt adjacent_difference(InputIt first, InputIt last, OutputIt d_first);
OutputIt adjacent_difference(InputIt first, InputIt last, OutputIt d_first, BinaryOperation op);
first
和 last
:输入序列的迭代器范围。d_first
:输出序列的起始迭代器。op
(可选):自定义二元操作(默认为减法)。std::vector<int> nums = {2, 4, 6, 8};
std::vector<int> result(4);
std::adjacent_difference(nums.begin(), nums.end(), result.begin()); // 输出 {2, 2, 2, 2}
std::iota
void iota(ForwardIt first, ForwardIt last, T value);
first
和 last
:目标序列的迭代器范围。value
:起始值(每次递增后赋值)。std::vector<int> nums(5);
std::iota(nums.begin(), nums.end(), 10); // 输出 {10, 11, 12, 13, 14}
accumulate
)或无副作用。在C++ STL中,随机数生成器用于生成伪随机数,主要由
头文件提供。它比传统的rand()
函数更灵活、更强大,支持多种分布类型和随机数引擎。
随机数引擎是生成随机数的核心组件,常见的引擎包括:
std::default_random_engine
:默认的随机数引擎,实现可能因编译器而异。std::mt19937
:基于梅森旋转算法的高质量随机数引擎(32位)。std::mt19937_64
:64位版本的梅森旋转引擎。随机数分布用于将引擎生成的随机数映射到特定的范围内或按特定概率分布生成。常见的分布包括:
std::uniform_int_distribution
:生成均匀分布的整数。std::uniform_real_distribution
:生成均匀分布的浮点数。std::normal_distribution
。std::bernoulli_distribution
(生成true
或false
)。#include
#include
int main() {
// 1. 初始化随机数引擎
std::random_device rd; // 用于获取随机种子
std::mt19937 gen(rd()); // 使用梅森旋转引擎
// 2. 定义分布(生成1到6的均匀整数,模拟骰子)
std::uniform_int_distribution<> dis(1, 6);
// 3. 生成随机数
for (int i = 0; i < 10; ++i) {
std::cout << dis(gen) << " ";
}
return 0;
}
std::random_device
获取真随机数作为种子,避免伪随机序列重复。std::mt19937
适合大多数场景,但初始化较慢。rand()
的区别valarray
是 C++ 标准模板库(STL)中的一个类模板,专门用于高效处理数值计算。它提供了对数值数组的支持,包括数学运算、切片、间接访问等功能,适用于科学计算和数值分析。
数学运算优化:
valarray
重载了常见的数学运算符(如 +
, -
, *
, /
),可以直接对整个数组进行逐元素运算。sin
, cos
, sqrt
)的逐元素操作。切片和间接访问:
slice
(切片)和 gslice
(广义切片)操作,可以高效地访问数组的子集。mask_array
和 indirect_array
用于条件筛选和间接索引访问。内存连续性:
valarray
通常以连续内存块存储数据,适合与 C 风格数组或低级数值库(如 BLAS)交互。#include
#include
int main() {
std::valarray<int> v1 = {1, 2, 3, 4, 5};
std::valarray<int> v2 = {5, 4, 3, 2, 1};
// 逐元素加法
std::valarray<int> v3 = v1 + v2;
// 输出结果
for (int n : v3) {
std::cout << n << ' ';
}
// 输出:6 6 6 6 6
}
size()
:返回数组的大小。sum()
:计算所有元素的和。min()
/ max()
:返回最小/最大值。apply(func)
:对每个元素应用函数 func
。valarray
的设计目标是高性能数值计算,但某些操作(如动态调整大小)可能不如 vector
灵活。valarray
的实现优化不足,实际性能可能因平台而异。valarray
适合需要频繁进行数值运算的场景,但在通用性上不如 vector
或 array
。