第30章 C++基本库

C++标准库概述

C++标准库是C++语言的核心组成部分,它提供了一系列的工具和组件,用于简化常见的编程任务。标准库的设计理念是”不要重复发明轮子”,通过使用标准库,开发者可以避免编写重复的代码,提高开发效率和代码质量。

标准库的组成

C++标准库主要由以下几个部分组成:

  1. 核心语言支持库:提供基本类型和语言特性的支持
  2. 容器库:提供各种数据结构,如向量、列表、映射等
  3. 算法库:提供各种算法,如排序、查找、变换等
  4. 迭代器库:提供遍历容器元素的方法
  5. 数值库:提供数值计算相关的功能
  6. 输入/输出库:提供文件和流的输入输出操作
  7. 字符串库:提供字符串处理功能
  8. 时间库:提供时间和日期相关的功能
  9. 本地化库:提供国际化和本地化支持
  10. 异常处理库:提供异常处理相关的功能
  11. 智能指针库:提供内存管理的智能指针
  12. 线程库:提供多线程编程支持

标准库的使用

要使用标准库,需要包含相应的头文件,例如:

1
2
3
4
5
6
#include <iostream>    // 输入/输出库
#include <vector> // 容器库
#include <algorithm> // 算法库
#include <string> // 字符串库
#include <memory> // 智能指针库
#include <thread> // 线程库

标准库中的组件都位于std命名空间中,因此在使用时需要加上std::前缀,或者使用using namespace std;来简化代码。

核心语言支持库

核心语言支持库提供了基本类型和语言特性的支持,包括:

  • 基本类型 - 如intdoublebool
  • 类型支持 - 如std::size_tstd::nullptr_t
  • 类型特性 - 如std::is_integralstd::is_floating_point
  • 动态内存管理 - 如newdeletestd::allocator
  • 错误处理 - 如std::exceptionstd::bad_alloc
  • initializer_list - 初始化列表支持
  • tuple - 元组类型
  • pair - 键值对类型
  • optional - 可选值类型(C++17+)
  • variant - 变体类型(C++17+)
  • any - 任意类型(C++17+)
  • source_location - 源代码位置(C++20+)
  • compare - 三路比较运算符支持(C++20+)
  • concepts - 模板参数约束(C++20+)
  • span - 非拥有式的连续内存范围视图(C++20+)
  • bit - 位操作工具(C++20+)
  • version - 库版本信息(C++20+)
  • expected - 可能失败的操作结果(C++23+)
  • mdspan - 多维数组视图(C++23+)
  • print - 格式化输出(C++23+)
  • to_underlying - 枚举转底层类型(C++23+)
  • static operator() - 静态调用运算符(C++23+)
  • deducing this - 推导this指针类型(C++23+)

基本类型

C++标准库提供了一些基本类型的定义和操作:

数值类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <limits>

int main() {
// 基本数值类型的大小
std::cout << "Size of char: " << sizeof(char) << " byte" << std::endl;
std::cout << "Size of int: " << sizeof(int) << " bytes" << std::endl;
std::cout << "Size of long: " << sizeof(long) << " bytes" << std::endl;
std::cout << "Size of double: " << sizeof(double) << " bytes" << std::endl;

// 数值类型的范围
std::cout << "Minimum value of int: " << std::numeric_limits<int>::min() << std::endl;
std::cout << "Maximum value of int: " << std::numeric_limits<int>::max() << std::endl;
std::cout << "Minimum value of double: " << std::numeric_limits<double>::min() << std::endl;
std::cout << "Maximum value of double: " << std::numeric_limits<double>::max() << std::endl;

return 0;
}

布尔类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>

int main() {
bool flag = true;
std::cout << "Flag value: " << flag << std::endl; // 输出 1

flag = false;
std::cout << "Flag value: " << flag << std::endl; // 输出 0

// 布尔表达式
bool result = (5 > 3) && (2 < 4);
std::cout << "Result: " << result << std::endl; // 输出 1

return 0;
}

C++23 打印库

C++23引入了std::printstd::println函数,提供了更简洁的格式化输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <print>
#include <string>

int main() {
// 基本打印
std::print("Hello, world!\n");

// 带参数的打印
std::print("The answer is {}\n", 42);

// 多个参数
std::print("Name: {}, Age: {}\n", "Alice", 30);

// 格式化选项
std::print("Pi is approximately {:.2f}\n", 3.14159);

// 使用println自动添加换行
std::println("Hello");
std::println("World");

// 带参数的println
std::println("Hello, {}", "C++23");

return 0;
}

C++23 期望类型

std::expected是C++23引入的类型,表示可能失败的操作结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <expected>
#include <print>
#include <string>

std::expected<int, std::string> divide(int a, int b) {
if (b == 0) {
return std::unexpected("Division by zero");
}
return a / b;
}

int main() {
auto result1 = divide(10, 2);
if (result1) {
std::println("Result: {}", *result1);
} else {
std::println("Error: {}", result1.error());
}

auto result2 = divide(10, 0);
if (result2) {
std::println("Result: {}", *result2);
} else {
std::println("Error: {}", result2.error());
}

return 0;
}

C++23 多维数组视图

std::mdspan是C++23引入的多维数组视图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <mdspan>
#include <print>
#include <vector>

int main() {
// 创建数据
std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

// 创建2x6的多维视图
std::mdspan<int, std::extents<size_t, 2, 6>> md(data.data());

// 修改元素
md(0, 0) = 100;
md(1, 5) = 200;

// 打印多维数组
std::println("2D array:");
for (size_t i = 0; i < md.extent(0); ++i) {
for (size_t j = 0; j < md.extent(1); ++j) {
std::print("{} ", md(i, j));
}
std::println();
}

return 0;
}

C++26 展望

C++26预计将引入以下重要特性:

  1. 静态反射 - 编译时类型信息操作
  2. 模式匹配 - 基于值或类型的模式匹配
  3. 执行策略 - 统一的并行算法接口
  4. 网络库 - 标准网络编程支持
  5. 数学库增强 - 更多数学函数和算法
  6. 模块系统完善 - 进一步改进模块功能

这些特性将进一步提升C++的表达能力和开发效率,使C++成为更现代、更强大的编程语言。

容器库

容器类型

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

int main() {
// 使用 nullptr(C++11+)
int* ptr = nullptr;
std::cout << "ptr is null: " << (ptr == nullptr) << std::endl;

// 传统的 NULL
int* oldPtr = NULL;
std::cout << "oldPtr is null: " << (oldPtr == NULL) << std::endl;

return 0;
}

类型支持

类型特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <type_traits>

int main() {
// 检查类型特性
std::cout << "Is int a fundamental type? " << std::is_fundamental<int>::value << std::endl;
std::cout << "Is int* a pointer? " << std::is_pointer<int*>::value << std::endl;
std::cout << "Is int const? " << std::is_const<int>::value << std::endl;
std::cout << "Is const int const? " << std::is_const<const int>::value << std::endl;
std::cout << "Is int& a reference? " << std::is_reference<int&>::value << std::endl;

// 类型转换
std::cout << "int to double: " << std::is_convertible<int, double>::value << std::endl;
std::cout << "double to int: " << std::is_convertible<double, int>::value << std::endl;

return 0;
}

类型工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <typeinfo>

class Base { public: virtual ~Base() {} };
class Derived : public Base {};

int main() {
// 获取类型信息
int i = 42;
double d = 3.14;
Base* b = new Derived();

std::cout << "Type of i: " << typeid(i).name() << std::endl;
std::cout << "Type of d: " << typeid(d).name() << std::endl;
std::cout << "Type of *b: " << typeid(*b).name() << std::endl;

delete b;

return 0;
}

C++20新特性

concepts库(C++20+)

concepts库提供了模板参数约束的支持,用于限制模板参数的类型要求,提高代码的可读性和错误信息的清晰度。

属性和方法:

概念描述参数
std::integral整型类型约束类型T
std::floating_point浮点型类型约束类型T
std::arithmetic算术类型约束类型T
std::totally_ordered全序类型约束类型T
std::copyable可复制类型约束类型T
std::movable可移动类型约束类型T
std::default_initializable可默认初始化类型约束类型T
std::constructible_from可从指定类型构造的类型约束类型T, 类型Args…
std::convertible_to可转换为指定类型的类型约束类型From, 类型To
std::same_as类型相同约束类型T, 类型U

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <concepts>
#include <iostream>

// 使用标准概念
std::integral auto add(std::integral auto a, std::integral auto b) {
return a + b;
}

// 自定义概念
template<typename T>
concept Printable = requires(T t) {
{ std::cout << t } -> std::same_as<std::ostream&>;
};

// 使用自定义概念
Printable auto print(Printable auto value) {
std::cout << value << std::endl;
return value;
}

// 复合概念
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;

Numeric auto multiply(Numeric auto a, Numeric auto b) {
return a * b;
}

int main() {
// 测试add函数
std::cout << add(1, 2) << std::endl; // 正确,int是整型
// std::cout << add(1.5, 2.5) << std::endl; // 错误,double不是整型

// 测试print函数
print(42); // 正确,int可打印
print(3.14); // 正确,double可打印
print("Hello"); // 正确,const char*可打印

// 测试multiply函数
std::cout << multiply(2, 3) << std::endl; // 正确,int是数值类型
std::cout << multiply(2.5, 3.5) << std::endl; // 正确,double是数值类型

return 0;
}

span库(C++20+)

span库提供了非拥有式的连续内存范围视图,用于安全地访问连续的内存区域,如数组、vector等。

属性和方法:

方法描述参数返回值
构造函数创建span指针和大小/容器span对象
data获取底层数据指针数据指针
size获取元素个数无符号整数
size_bytes获取字节大小无符号整数
empty检查是否为空布尔值
front获取第一个元素元素引用
back获取最后一个元素元素引用
operator[]访问指定位置的元素索引元素引用
begin返回起始迭代器迭代器
end返回结束迭代器迭代器

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <span>
#include <vector>

// 使用span作为函数参数
void print_span(std::span<int> s) {
std::cout << "Span size: " << s.size() << std::endl;
for (auto i : s) {
std::cout << i << " ";
}
std::cout << std::endl;
}

int main() {
// 从数组创建span
int arr[] = {1, 2, 3, 4, 5};
std::span<int> s1(arr);
print_span(s1);

// 从vector创建span
std::vector<int> vec = {6, 7, 8, 9, 10};
std::span<int> s2(vec);
print_span(s2);

// 创建子span
std::span<int> s3 = s1.subspan(1, 3); // 从索引1开始,长度为3
print_span(s3);

// 修改span中的元素(会修改原始数据)
if (!s1.empty()) {
s1[0] = 100;
std::cout << "Modified arr[0]: " << arr[0] << std::endl;
}

return 0;
}

bit库(C++20+)

bit库提供了位操作的工具函数,用于处理位级别的操作。

属性和方法:

函数描述参数返回值
std::bit_width获取表示值所需的位数无符号整数无符号整数
std::bit_ceil获取大于等于值的最小2的幂无符号整数无符号整数
std::bit_floor获取小于等于值的最大2的幂无符号整数无符号整数
std::countl_zero计算前导零的个数无符号整数无符号整数
std::countr_zero计算尾随零的个数无符号整数无符号整数
std::countl_one计算前导一的个数无符号整数无符号整数
std::countr_one计算尾随一的个数无符号整数无符号整数
std::popcount计算置位的个数无符号整数无符号整数
std::rotl向左循环移位无符号整数, 移位量无符号整数
std::rotr向右循环移位无符号整数, 移位量无符号整数
std::byteswap交换字节顺序无符号整数无符号整数

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <bit>

int main() {
unsigned int x = 42; // 二进制: 101010

std::cout << "x = " << x << std::endl;
std::cout << "bit_width(x) = " << std::bit_width(x) << std::endl;
std::cout << "bit_ceil(x) = " << std::bit_ceil(x) << std::endl;
std::cout << "bit_floor(x) = " << std::bit_floor(x) << std::endl;
std::cout << "countl_zero(x) = " << std::countl_zero(x) << std::endl;
std::cout << "countr_zero(x) = " << std::countr_zero(x) << std::endl;
std::cout << "popcount(x) = " << std::popcount(x) << std::endl;

unsigned int y = 0b10101010;
std::cout << "y = " << y << std::endl;
std::cout << "rotl(y, 1) = " << std::rotl(y, 1) << std::endl;
std::cout << "rotr(y, 1) = " << std::rotr(y, 1) << std::endl;
std::cout << "byteswap(y) = " << std::byteswap(y) << std::endl;

return 0;
}

容器库

序列容器

vector

vector是最常用的序列容器,它提供了动态数组的功能,支持随机访问。

属性和方法:

方法描述参数返回值
push_back在末尾添加元素元素值
pop_back移除末尾元素
size返回元素个数无符号整数
empty检查是否为空布尔值
clear清空容器
at访问指定位置的元素(带边界检查)索引元素引用
operator[]访问指定位置的元素(无边界检查)索引元素引用
begin返回指向第一个元素的迭代器迭代器
end返回指向最后一个元素之后的迭代器迭代器
insert在指定位置插入元素迭代器位置, 元素值指向插入元素的迭代器
erase删除指定位置的元素迭代器位置指向删除元素之后的迭代器
reserve预分配内存容量大小
resize调整容器大小新大小, 填充值(可选)

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <iostream>
#include <vector>

int main() {
// 创建vector
std::vector<int> vec;

// 添加元素
vec.push_back(10);
vec.push_back(20);
vec.push_back(30);
vec.push_back(40);
vec.push_back(50);

// 访问元素
std::cout << "First element: " << vec[0] << std::endl;
std::cout << "Second element: " << vec.at(1) << std::endl;
std::cout << "Last element: " << vec.back() << std::endl;

// 修改元素
vec[0] = 100;
std::cout << "Modified first element: " << vec[0] << std::endl;

// 遍历元素
std::cout << "All elements: ";
for (size_t i = 0; i < vec.size(); ++i) {
std::cout << vec[i] << " ";
}
std::cout << std::endl;

// 使用迭代器遍历
std::cout << "All elements (iterator): ";
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;

// 使用范围for循环
std::cout << "All elements (range-based): ";
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// 插入元素
auto it = vec.begin();
++it; // 移动到第二个位置
vec.insert(it, 15);
std::cout << "After insert: ";
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// 删除元素
it = vec.begin();
++it; // 移动到第二个位置
vec.erase(it);
std::cout << "After erase: ";
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// 检查大小
std::cout << "Size: " << vec.size() << std::endl;
std::cout << "Empty: " << (vec.empty() ? "Yes" : "No") << std::endl;

// 清空容器
vec.clear();
std::cout << "After clear, size: " << vec.size() << std::endl;
std::cout << "Empty: " << (vec.empty() ? "Yes" : "No") << std::endl;

return 0;
}

list

list是双向链表,支持双向遍历,任意位置的插入和删除操作效率高。

属性和方法:

方法描述参数返回值
push_front在头部添加元素元素值
push_back在尾部添加元素元素值
pop_front移除头部元素
pop_back移除尾部元素
size返回元素个数无符号整数
empty检查是否为空布尔值
clear清空容器
front访问头部元素元素引用
back访问尾部元素元素引用
begin返回指向第一个元素的迭代器迭代器
end返回指向最后一个元素之后的迭代器迭代器
insert在指定位置插入元素迭代器位置, 元素值指向插入元素的迭代器
erase删除指定位置的元素迭代器位置指向删除元素之后的迭代器
sort排序元素
reverse反转元素顺序
splice移动元素到另一个list迭代器位置, 源list

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <list>

int main() {
// 创建list
std::list<int> lst;

// 添加元素
lst.push_back(10);
lst.push_back(20);
lst.push_front(5);
lst.push_back(30);

// 访问元素
std::cout << "Front element: " << lst.front() << std::endl;
std::cout << "Back element: " << lst.back() << std::endl;

// 遍历元素
std::cout << "All elements: ";
for (int num : lst) {
std::cout << num << " ";
}
std::cout << std::endl;

// 插入元素
auto it = lst.begin();
++it; // 移动到第二个位置
lst.insert(it, 15);
std::cout << "After insert: ";
for (int num : lst) {
std::cout << num << " ";
}
std::cout << std::endl;

// 删除元素
it = lst.begin();
++it; // 移动到第二个位置
lst.erase(it);
std::cout << "After erase: ";
for (int num : lst) {
std::cout << num << " ";
}
std::cout << std::endl;

// 排序
lst.sort();
std::cout << "After sort: ";
for (int num : lst) {
std::cout << num << " ";
}
std::cout << std::endl;

// 反转
lst.reverse();
std::cout << "After reverse: ";
for (int num : lst) {
std::cout << num << " ";
}
std::cout << std::endl;

// 检查大小
std::cout << "Size: " << lst.size() << std::endl;
std::cout << "Empty: " << (lst.empty() ? "Yes" : "No") << std::endl;

// 清空容器
lst.clear();
std::cout << "After clear, size: " << lst.size() << std::endl;

return 0;
}

deque

deque是双端队列,支持两端快速插入和删除操作,也支持随机访问。

属性和方法:

方法描述参数返回值
push_front在头部添加元素元素值
push_back在尾部添加元素元素值
pop_front移除头部元素
pop_back移除尾部元素
size返回元素个数无符号整数
empty检查是否为空布尔值
clear清空容器
front访问头部元素元素引用
back访问尾部元素元素引用
at访问指定位置的元素(带边界检查)索引元素引用
operator[]访问指定位置的元素(无边界检查)索引元素引用
begin返回指向第一个元素的迭代器迭代器
end返回指向最后一个元素之后的迭代器迭代器
insert在指定位置插入元素迭代器位置, 元素值指向插入元素的迭代器
erase删除指定位置的元素迭代器位置指向删除元素之后的迭代器

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <deque>

int main() {
// 创建deque
std::deque<int> dq;

// 添加元素
dq.push_back(10);
dq.push_back(20);
dq.push_front(5);
dq.push_back(30);

// 访问元素
std::cout << "Front element: " << dq.front() << std::endl;
std::cout << "Back element: " << dq.back() << std::endl;
std::cout << "Element at index 1: " << dq[1] << std::endl;
std::cout << "Element at index 2: " << dq.at(2) << std::endl;

// 遍历元素
std::cout << "All elements: ";
for (int num : dq) {
std::cout << num << " ";
}
std::cout << std::endl;

// 插入元素
auto it = dq.begin();
++it; // 移动到第二个位置
dq.insert(it, 15);
std::cout << "After insert: ";
for (int num : dq) {
std::cout << num << " ";
}
std::cout << std::endl;

// 删除元素
it = dq.begin();
++it; // 移动到第二个位置
dq.erase(it);
std::cout << "After erase: ";
for (int num : dq) {
std::cout << num << " ";
}
std::cout << std::endl;

// 检查大小
std::cout << "Size: " << dq.size() << std::endl;
std::cout << "Empty: " << (dq.empty() ? "Yes" : "No") << std::endl;

// 清空容器
dq.clear();
std::cout << "After clear, size: " << dq.size() << std::endl;

return 0;
}

关联容器

map

map是有序映射,存储键值对,键唯一,按照键的升序排列。

属性和方法:

方法描述参数返回值
insert插入键值对键值对插入结果(迭代器和布尔值)
erase删除键对应的元素键或迭代器删除的元素个数
find查找键对应的元素指向元素的迭代器
count统计键的出现次数出现次数(0或1)
size返回元素个数无符号整数
empty检查是否为空布尔值
clear清空容器
begin返回指向第一个元素的迭代器迭代器
end返回指向最后一个元素之后的迭代器迭代器
operator[]访问或插入键对应的元素元素引用
at访问键对应的元素(带边界检查)元素引用

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <map>
#include <string>

int main() {
// 创建map
std::map<std::string, int> scores;

// 添加元素
scores["Alice"] = 95;
scores["Bob"] = 85;
scores["Charlie"] = 90;
scores.insert({"David", 88});

// 访问元素
std::cout << "Alice's score: " << scores["Alice"] << std::endl;
std::cout << "Bob's score: " << scores.at("Bob") << std::endl;

// 遍历元素
std::cout << "All scores: " << std::endl;
for (const auto& pair : scores) {
std::cout << pair.first << ": " << pair.second << std::endl;
}

// 查找元素
auto it = scores.find("Charlie");
if (it != scores.end()) {
std::cout << "Found Charlie: " << it->second << std::endl;
} else {
std::cout << "Charlie not found" << std::endl;
}

// 统计元素
std::cout << "Number of entries for Alice: " << scores.count("Alice") << std::endl;
std::cout << "Number of entries for Eve: " << scores.count("Eve") << std::endl;

// 删除元素
scores.erase("Bob");
std::cout << "After erasing Bob: " << std::endl;
for (const auto& pair : scores) {
std::cout << pair.first << ": " << pair.second << std::endl;
}

// 检查大小
std::cout << "Size: " << scores.size() << std::endl;
std::cout << "Empty: " << (scores.empty() ? "Yes" : "No") << std::endl;

// 清空容器
scores.clear();
std::cout << "After clear, size: " << scores.size() << std::endl;

return 0;
}

set

set是有序集合,存储唯一的键,按照键的升序排列。

属性和方法:

方法描述参数返回值
insert插入元素元素值插入结果(迭代器和布尔值)
erase删除元素元素值或迭代器删除的元素个数
find查找元素元素值指向元素的迭代器
count统计元素的出现次数元素值出现次数(0或1)
size返回元素个数无符号整数
empty检查是否为空布尔值
clear清空容器
begin返回指向第一个元素的迭代器迭代器
end返回指向最后一个元素之后的迭代器迭代器
lower_bound返回大于等于给定值的第一个元素的迭代器元素值迭代器
upper_bound返回大于给定值的第一个元素的迭代器元素值迭代器

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <set>

int main() {
// 创建set
std::set<int> s;

// 添加元素
s.insert(10);
s.insert(20);
s.insert(15);
s.insert(5);
s.insert(25);
s.insert(10); // 重复元素,不会插入

// 遍历元素(自动排序)
std::cout << "All elements: ";
for (int num : s) {
std::cout << num << " ";
}
std::cout << std::endl;

// 查找元素
auto it = s.find(15);
if (it != s.end()) {
std::cout << "Found 15" << std::endl;
} else {
std::cout << "15 not found" << std::endl;
}

// 统计元素
std::cout << "Count of 10: " << s.count(10) << std::endl;
std::cout << "Count of 30: " << s.count(30) << std::endl;

// 删除元素
s.erase(20);
std::cout << "After erasing 20: ";
for (int num : s) {
std::cout << num << " ";
}
std::cout << std::endl;

// 边界查找
it = s.lower_bound(12);
std::cout << "Lower bound of 12: " << *it << std::endl;

it = s.upper_bound(12);
std::cout << "Upper bound of 12: " << *it << std::endl;

// 检查大小
std::cout << "Size: " << s.size() << std::endl;
std::cout << "Empty: " << (s.empty() ? "Yes" : "No") << std::endl;

// 清空容器
s.clear();
std::cout << "After clear, size: " << s.size() << std::endl;

return 0;
}

无序容器

unordered_map

unordered_map是无序映射,存储键值对,键唯一,使用哈希表实现,查找效率高。

属性和方法:

方法描述参数返回值
insert插入键值对键值对插入结果(迭代器和布尔值)
erase删除键对应的元素键或迭代器删除的元素个数
find查找键对应的元素指向元素的迭代器
count统计键的出现次数出现次数(0或1)
size返回元素个数无符号整数
empty检查是否为空布尔值
clear清空容器
begin返回指向第一个元素的迭代器迭代器
end返回指向最后一个元素之后的迭代器迭代器
operator[]访问或插入键对应的元素元素引用
at访问键对应的元素(带边界检查)元素引用
bucket_count返回桶的数量无符号整数
load_factor返回负载因子浮点数
rehash重新哈希桶的数量

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <unordered_map>
#include <string>

int main() {
// 创建unordered_map
std::unordered_map<std::string, int> scores;

// 添加元素
scores["Alice"] = 95;
scores["Bob"] = 85;
scores["Charlie"] = 90;
scores.insert({"David", 88});

// 访问元素
std::cout << "Alice's score: " << scores["Alice"] << std::endl;
std::cout << "Bob's score: " << scores.at("Bob") << std::endl;

// 遍历元素(无序)
std::cout << "All scores: " << std::endl;
for (const auto& pair : scores) {
std::cout << pair.first << ": " << pair.second << std::endl;
}

// 查找元素
auto it = scores.find("Charlie");
if (it != scores.end()) {
std::cout << "Found Charlie: " << it->second << std::endl;
} else {
std::cout << "Charlie not found" << std::endl;
}

// 删除元素
scores.erase("Bob");
std::cout << "After erasing Bob: " << std::endl;
for (const auto& pair : scores) {
std::cout << pair.first << ": " << pair.second << std::endl;
}

// 桶相关操作
std::cout << "Bucket count: " << scores.bucket_count() << std::endl;
std::cout << "Load factor: " << scores.load_factor() << std::endl;

// 检查大小
std::cout << "Size: " << scores.size() << std::endl;
std::cout << "Empty: " << (scores.empty() ? "Yes" : "No") << std::endl;

// 清空容器
scores.clear();
std::cout << "After clear, size: " << scores.size() << std::endl;

return 0;
}

unordered_set

unordered_set是无序集合,存储唯一的键,使用哈希表实现,查找效率高。

属性和方法:

方法描述参数返回值
insert插入元素元素值插入结果(迭代器和布尔值)
erase删除元素元素值或迭代器删除的元素个数
find查找元素元素值指向元素的迭代器
count统计元素的出现次数元素值出现次数(0或1)
size返回元素个数无符号整数
empty检查是否为空布尔值
clear清空容器
begin返回指向第一个元素的迭代器迭代器
end返回指向最后一个元素之后的迭代器迭代器
bucket_count返回桶的数量无符号整数
load_factor返回负载因子浮点数
rehash重新哈希桶的数量

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <unordered_set>

int main() {
// 创建unordered_set
std::unordered_set<int> s;

// 添加元素
s.insert(10);
s.insert(20);
s.insert(15);
s.insert(5);
s.insert(25);
s.insert(10); // 重复元素,不会插入

// 遍历元素(无序)
std::cout << "All elements: ";
for (int num : s) {
std::cout << num << " ";
}
std::cout << std::endl;

// 查找元素
auto it = s.find(15);
if (it != s.end()) {
std::cout << "Found 15" << std::endl;
} else {
std::cout << "15 not found" << std::endl;
}

// 删除元素
s.erase(20);
std::cout << "After erasing 20: ";
for (int num : s) {
std::cout << num << " ";
}
std::cout << std::endl;

// 桶相关操作
std::cout << "Bucket count: " << s.bucket_count() << std::endl;
std::cout << "Load factor: " << s.load_factor() << std::endl;

// 检查大小
std::cout << "Size: " << s.size() << std::endl;
std::cout << "Empty: " << (s.empty() ? "Yes" : "No") << std::endl;

// 清空容器
s.clear();
std::cout << "After clear, size: " << s.size() << std::endl;

return 0;
}

算法库

ranges库(C++20+)

C++20引入的ranges库是对传统算法库的扩展,提供了更灵活、更简洁的迭代器和算法使用方式,支持链式操作和更直观的语法。

属性和方法:

算法描述参数返回值
std::ranges::sort排序范围范围
std::ranges::find查找元素范围, 值迭代器
std::ranges::find_if条件查找范围, 谓词迭代器
std::ranges::transform变换范围输入范围, 输出范围, 变换函数输出迭代器
std::ranges::filter过滤范围范围, 谓词视图
std::ranges::transform_view变换视图范围, 变换函数视图
std::ranges::reverse反转范围范围
std::ranges::count计数元素范围, 值无符号整数
std::ranges::count_if条件计数范围, 谓词无符号整数
std::ranges::for_each遍历范围范围, 函数函数

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 传统算法方式
std::cout << "传统方式 - 偶数: ";
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
if (*it % 2 == 0) {
std::cout << *it << " ";
}
}
std::cout << std::endl;

// ranges方式 - 链式操作
std::cout << "Ranges方式 - 偶数的平方: ";
auto result = numbers | std::views::filter([](int n) { return n % 2 == 0; })
| std::views::transform([](int n) { return n * n; });

for (auto n : result) {
std::cout << n << " ";
}
std::cout << std::endl;

// 使用ranges算法
std::cout << "Ranges排序: ";
std::ranges::sort(numbers, std::greater{});
for (auto n : numbers) {
std::cout << n << " ";
}
std::cout << std::endl;

// 复合视图
std::cout << "复合视图 - 大于5的数的平方根: ";
auto complex_view = numbers | std::views::filter([](int n) { return n > 5; })
| std::views::transform([](int n) { return std::sqrt(n); });

for (auto n : complex_view) {
std::cout << n << " ";
}
std::cout << std::endl;

return 0;
}

查找算法

属性和方法:

算法描述参数返回值
find查找第一个等于给定值的元素开始迭代器, 结束迭代器, 值指向找到元素的迭代器
find_if查找第一个满足条件的元素开始迭代器, 结束迭代器, 谓词指向找到元素的迭代器
find_if_not查找第一个不满足条件的元素开始迭代器, 结束迭代器, 谓词指向找到元素的迭代器
count统计等于给定值的元素个数开始迭代器, 结束迭代器, 值元素个数
count_if统计满足条件的元素个数开始迭代器, 结束迭代器, 谓词元素个数
search查找子序列开始迭代器, 结束迭代器, 子序列开始, 子序列结束指向子序列开始的迭代器
binary_search二分查找(要求已排序)开始迭代器, 结束迭代器, 值布尔值

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> vec = {5, 2, 8, 1, 9, 3, 7, 4, 6};

// find
auto it = std::find(vec.begin(), vec.end(), 5);
if (it != vec.end()) {
std::cout << "Found 5 at position: " << std::distance(vec.begin(), it) << std::endl;
}

// find_if
it = std::find_if(vec.begin(), vec.end(), [](int x) { return x > 5; });
if (it != vec.end()) {
std::cout << "First element > 5: " << *it << " at position: " << std::distance(vec.begin(), it) << std::endl;
}

// count
int cnt = std::count(vec.begin(), vec.end(), 5);
std::cout << "Count of 5: " << cnt << std::endl;

// count_if
cnt = std::count_if(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; });
std::cout << "Count of even numbers: " << cnt << std::endl;

// binary_search (需要先排序)
std::sort(vec.begin(), vec.end());
bool found = std::binary_search(vec.begin(), vec.end(), 5);
std::cout << "5 found in sorted vector: " << (found ? "Yes" : "No") << std::endl;

// 输出排序后的向量
std::cout << "Sorted vector: ";
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

return 0;
}

排序算法

属性和方法:

算法描述参数返回值
sort排序元素开始迭代器, 结束迭代器
stable_sort稳定排序元素开始迭代器, 结束迭代器
partial_sort部分排序元素开始迭代器, 中间迭代器, 结束迭代器
nth_element找到第n大的元素开始迭代器, nth迭代器, 结束迭代器
merge合并两个已排序的范围开始1, 结束1, 开始2, 结束2, 目标开始指向目标范围末尾的迭代器
reverse反转元素顺序开始迭代器, 结束迭代器

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> vec = {5, 2, 8, 1, 9, 3, 7, 4, 6};

// sort
std::sort(vec.begin(), vec.end());
std::cout << "Sorted: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// reverse
std::reverse(vec.begin(), vec.end());
std::cout << "Reversed: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// sort with custom comparator
std::sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; });
std::cout << "Sorted in descending order: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// partial_sort
std::vector<int> vec2 = {9, 7, 5, 3, 1, 8, 6, 4, 2};
std::partial_sort(vec2.begin(), vec2.begin() + 5, vec2.end());
std::cout << "Partial sorted (first 5 elements): " << std::endl;
for (int num : vec2) {
std::cout << num << " ";
}
std::cout << std::endl;

// nth_element
std::vector<int> vec3 = {9, 7, 5, 3, 1, 8, 6, 4, 2};
std::nth_element(vec3.begin(), vec3.begin() + 4, vec3.end());
std::cout << "After nth_element (5th element): " << std::endl;
for (int num : vec3) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "5th element: " << vec3[4] << std::endl;

return 0;
}

修改算法

属性和方法:

算法描述参数返回值
copy复制元素开始迭代器, 结束迭代器, 目标开始指向目标范围末尾的迭代器
move移动元素开始迭代器, 结束迭代器, 目标开始指向目标范围末尾的迭代器
fill填充元素开始迭代器, 结束迭代器, 值
replace替换元素开始迭代器, 结束迭代器, 旧值, 新值
replace_if条件替换元素开始迭代器, 结束迭代器, 谓词, 新值
swap交换两个元素元素1, 元素2
transform转换元素开始迭代器, 结束迭代器, 目标开始, 一元操作指向目标范围末尾的迭代器
remove移除元素开始迭代器, 结束迭代器, 值指向新范围末尾的迭代器
remove_if条件移除元素开始迭代器, 结束迭代器, 谓词指向新范围末尾的迭代器
unique移除重复元素开始迭代器, 结束迭代器指向新范围末尾的迭代器

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> vec = {5, 2, 8, 1, 9, 3, 7, 4, 6};
std::vector<int> dest(vec.size());

// copy
std::copy(vec.begin(), vec.end(), dest.begin());
std::cout << "Copied: " << std::endl;
for (int num : dest) {
std::cout << num << " ";
}
std::cout << std::endl;

// fill
std::fill(dest.begin(), dest.end(), 0);
std::cout << "Filled with 0: " << std::endl;
for (int num : dest) {
std::cout << num << " ";
}
std::cout << std::endl;

// replace
std::replace(vec.begin(), vec.end(), 5, 50);
std::cout << "After replacing 5 with 50: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// transform
std::transform(vec.begin(), vec.end(), dest.begin(), [](int x) { return x * 2; });
std::cout << "After doubling: " << std::endl;
for (int num : dest) {
std::cout << num << " ";
}
std::cout << std::endl;

// remove (需要配合erase使用)
auto new_end = std::remove(vec.begin(), vec.end(), 50);
vec.erase(new_end, vec.end());
std::cout << "After removing 50: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// unique (需要先排序)
std::sort(vec.begin(), vec.end());
new_end = std::unique(vec.begin(), vec.end());
vec.erase(new_end, vec.end());
std::cout << "After removing duplicates: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

return 0;
}

数值算法

属性和方法:

算法描述参数返回值
accumulate累加开始迭代器, 结束迭代器, 初始值累加结果
inner_product内积开始1, 结束1, 开始2, 初始值内积结果
adjacent_difference相邻元素的差开始迭代器, 结束迭代器, 目标开始指向目标范围末尾的迭代器
partial_sum部分和开始迭代器, 结束迭代器, 目标开始指向目标范围末尾的迭代器

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <vector>
#include <numeric>

int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};

// accumulate
int sum = std::accumulate(vec.begin(), vec.end(), 0);
std::cout << "Sum: " << sum << std::endl;

// accumulate with custom operation
int product = std::accumulate(vec.begin(), vec.end(), 1, [](int a, int b) { return a * b; });
std::cout << "Product: " << product << std::endl;

// inner_product
std::vector<int> vec2 = {6, 7, 8, 9, 10};
int inner_prod = std::inner_product(vec.begin(), vec.end(), vec2.begin(), 0);
std::cout << "Inner product: " << inner_prod << std::endl;

// adjacent_difference
std::vector<int> diff(vec.size());
std::adjacent_difference(vec.begin(), vec.end(), diff.begin());
std::cout << "Adjacent differences: " << std::endl;
for (int num : diff) {
std::cout << num << " ";
}
std::cout << std::endl;

// partial_sum
std::vector<int> partial(vec.size());
std::partial_sum(vec.begin(), vec.end(), partial.begin());
std::cout << "Partial sums: " << std::endl;
for (int num : partial) {
std::cout << num << " ";
}
std::cout << std::endl;

return 0;
}

字符串库

format库(C++20+)

C++20引入的format库提供了类型安全的字符串格式化功能,是对传统printf函数的现代替代。

属性和方法:

函数描述参数返回值
std::format格式化字符串格式字符串, 参数…std::string
std::format_to格式化到输出迭代器输出迭代器, 格式字符串, 参数…输出迭代器
std::format_to_n格式化到输出迭代器(带大小限制)输出迭代器, 大小, 格式字符串, 参数…结果结构体
std::formatted_size计算格式化后的大小格式字符串, 参数…无符号整数

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <format>
#include <string>

int main() {
// 基本格式化
std::string s1 = std::format("Hello, {}", "world");
std::cout << s1 << std::endl; // 输出: Hello, world

// 位置参数
std::string s2 = std::format("{1}, {0}", "world", "Hello");
std::cout << s2 << std::endl; // 输出: Hello, world

// 类型安全
int x = 42;
double y = 3.14;
std::string s4 = std::format("x = {}, y = {:.2f}", x, y);
std::cout << s4 << std::endl; // 输出: x = 42, y = 3.14

// 格式化到字符数组
char buffer[100];
std::format_to(std::begin(buffer), "The answer is {}", 42);
std::cout << buffer << std::endl; // 输出: The answer is 42

// 计算格式化后的大小
size_t size = std::formatted_size("Hello, {}", "world");
std::cout << "Formatted size: " << size << std::endl; // 输出: 12

return 0;
}

string类

属性和方法:

方法描述参数返回值
size / length返回字符串长度无符号整数
empty检查是否为空布尔值
clear清空字符串
operator[]访问指定位置的字符索引字符引用
at访问指定位置的字符(带边界检查)索引字符引用
front访问第一个字符字符引用
back访问最后一个字符字符引用
append追加字符串字符串字符串引用
operator+=追加字符串字符串字符串引用
insert插入字符串位置, 字符串字符串引用
erase删除子字符串位置, 长度字符串引用
replace替换子字符串位置, 长度, 字符串字符串引用
substr获取子字符串位置, 长度子字符串
find查找子字符串子字符串位置索引
rfind反向查找子字符串子字符串位置索引
compare比较字符串字符串整数(-1, 0, 1)
c_str返回C风格字符串const char*
data返回字符串数据const char*
capacity返回容量无符号整数
reserve预分配容量容量大小
shrink_to_fit收缩容量

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <string>

int main() {
// 创建字符串
std::string s1;
std::string s2("Hello");
std::string s3(5, 'a');
std::string s4(s2);

std::cout << "s1: " << s1 << std::endl;
std::cout << "s2: " << s2 << std::endl;
std::cout << "s3: " << s3 << std::endl;
std::cout << "s4: " << s4 << std::endl;

// 字符串操作
s1 = "World";
std::cout << "s1 after assignment: " << s1 << std::endl;

// 连接字符串
std::string s5 = s2 + " " + s1;
std::cout << "s5: " << s5 << std::endl;

s5 += "!";
std::cout << "s5 after +=: " << s5 << std::endl;

// 访问字符
std::cout << "First character of s5: " << s5[0] << std::endl;
std::cout << "Last character of s5: " << s5.back() << std::endl;

// 修改字符
s5[0] = 'h';
std::cout << "s5 after modifying first character: " << s5 << std::endl;

// 字符串长度
std::cout << "Length of s5: " << s5.length() << std::endl;
std::cout << "Size of s5: " << s5.size() << std::endl;

// 子字符串
std::string substr = s5.substr(0, 5);
std::cout << "Substring (0, 5): " << substr << std::endl;

// 查找
size_t pos = s5.find("World");
if (pos != std::string::npos) {
std::cout << "Found \"World\" at position: " << pos << std::endl;
}

// 替换
s5.replace(pos, 5, "C++");
std::cout << "s5 after replace: " << s5 << std::endl;

// 插入
s5.insert(6, " ");
std::cout << "s5 after insert: " << s5 << std::endl;

// 删除
s5.erase(6, 1);
std::cout << "s5 after erase: " << s5 << std::endl;

// 比较
if (s2 == s4) {
std::cout << "s2 == s4" << std::endl;
}

// C风格字符串
const char* cstr = s5.c_str();
std::cout << "C-style string: " << cstr << std::endl;

return 0;
}

输入/输出库

标准输入/输出

属性和方法:

方法描述参数返回值
std::cout标准输出流各种类型的值流对象引用
std::cin标准输入流变量引用流对象引用
std::cerr标准错误流各种类型的值流对象引用
std::clog标准日志流各种类型的值流对象引用
std::endl换行并刷新缓冲区流操纵符
std::flush刷新缓冲区流操纵符
std::setw设置字段宽度宽度流操纵符
std::setprecision设置精度精度流操纵符
std::fixed使用固定小数点表示流操纵符
std::scientific使用科学计数法表示流操纵符

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <iomanip>

int main() {
// 输出
std::cout << "Hello, World!" << std::endl;
std::cout << "The answer is " << 42 << std::endl;
std::cout << "Pi is approximately " << 3.14159 << std::endl;

// 错误输出
std::cerr << "Error: Something went wrong!" << std::endl;

// 日志输出
std::clog << "Log: Operation completed" << std::endl;

// 输入
int x;
std::cout << "Enter a number: ";
std::cin >> x;
std::cout << "You entered: " << x << std::endl;

// 读取字符串
std::string name;
std::cout << "Enter your name: ";
std::cin >> name;
std::cout << "Hello, " << name << "!" << std::endl;

// 读取一行
std::string line;
std::cout << "Enter a line: ";
std::cin.ignore(); // 忽略之前的换行符
std::getline(std::cin, line);
std::cout << "You entered: " << line << std::endl;

// 格式化输出
double pi = 3.141592653589793;
std::cout << "Pi with 2 decimal places: " << std::fixed << std::setprecision(2) << pi << std::endl;
std::cout << "Pi in scientific notation: " << std::scientific << std::setprecision(4) << pi << std::endl;

// 设置宽度
std::cout << "Name" << std::setw(10) << "Age" << std::endl;
std::cout << "Alice" << std::setw(10) << 25 << std::endl;
std::cout << "Bob" << std::setw(10) << 30 << std::endl;

return 0;
}

文件输入/输出

属性和方法:

方法描述参数返回值
std::ifstream输入文件流文件名, 打开模式流对象
std::ofstream输出文件流文件名, 打开模式流对象
std::fstream文件流文件名, 打开模式流对象
open打开文件文件名, 打开模式
close关闭文件
is_open检查文件是否打开布尔值
good检查流状态是否良好布尔值
eof检查是否到达文件末尾布尔值
fail检查是否发生失败布尔值
bad检查是否发生严重错误布尔值
clear清除错误状态流对象引用
seekg设置输入位置指针偏移量, 基准位置流对象引用
tellg获取输入位置指针位置
seekp设置输出位置指针偏移量, 基准位置流对象引用
tellp获取输出位置指针位置

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <fstream>
#include <string>

int main() {
// 写入文件
std::ofstream outFile("example.txt");

if (outFile.is_open()) {
outFile << "Hello, File!" << std::endl;
outFile << "The answer is " << 42 << std::endl;
outFile << "Pi is approximately " << 3.14159 << std::endl;
outFile.close();
std::cout << "File written successfully!" << std::endl;
} else {
std::cerr << "Error opening file for writing!" << std::endl;
}

// 读取文件
std::ifstream inFile("example.txt");

if (inFile.is_open()) {
std::string line;
while (std::getline(inFile, line)) {
std::cout << line << std::endl;
}
inFile.close();
} else {
std::cerr << "Error opening file for reading!" << std::endl;
}

// 读写文件
std::fstream file("example.txt", std::ios::in | std::ios::out);

if (file.is_open()) {
// 读取第一行
std::string line;
std::getline(file, line);
std::cout << "First line: " << line << std::endl;

// 定位到文件末尾
file.seekp(0, std::ios::end);
file << "Appended line" << std::endl;

file.close();
} else {
std::cerr << "Error opening file for reading and writing!" << std::endl;
}

return 0;
}

智能指针库

unique_ptr

unique_ptr是独占所有权的智能指针,一个对象只能被一个unique_ptr拥有。

属性和方法:

方法描述参数返回值
std::make_unique创建unique_ptr构造参数unique_ptr对象
operator*解引用指针引用
operator->访问成员指针
get获取原始指针原始指针
release释放所有权原始指针
reset重置指针原始指针(可选)
swap交换指针另一个unique_ptr
operator bool检查是否为空布尔值

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <memory>

class MyClass {
private:
int value;

public:
MyClass(int v) : value(v) {
std::cout << "MyClass constructed: " << value << std::endl;
}

~MyClass() {
std::cout << "MyClass destructed: " << value << std::endl;
}

void print() {
std::cout << "Value: " << value << std::endl;
}
};

int main() {
// 创建unique_ptr
std::unique_ptr<MyClass> ptr1(new MyClass(10));
auto ptr2 = std::make_unique<MyClass>(20);

// 访问成员
ptr1->print();
ptr2->print();

// 释放所有权
MyClass* rawPtr = ptr1.release();
std::cout << "After release, ptr1 is null: " << (!ptr1 ? "Yes" : "No") << std::endl;
delete rawPtr; // 需要手动删除

// 重置
ptr2.reset(new MyClass(30));
ptr2->print();

// 移动语义
std::unique_ptr<MyClass> ptr3 = std::move(ptr2);
std::cout << "After move, ptr2 is null: " << (!ptr2 ? "Yes" : "No") << std::endl;
ptr3->print();

// 自动析构
{
auto ptr4 = std::make_unique<MyClass>(40);
ptr4->print();
} // ptr4超出作用域,自动析构

return 0;
}

shared_ptr

shared_ptr是共享所有权的智能指针,多个shared_ptr可以拥有同一个对象。

属性和方法:

方法描述参数返回值
std::make_shared创建shared_ptr构造参数shared_ptr对象
operator*解引用指针引用
operator->访问成员指针
get获取原始指针原始指针
reset重置指针原始指针(可选)
swap交换指针另一个shared_ptr
use_count获取引用计数无符号整数
unique检查是否唯一布尔值
operator bool检查是否为空布尔值

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <memory>

class MyClass {
private:
int value;

public:
MyClass(int v) : value(v) {
std::cout << "MyClass constructed: " << value << std::endl;
}

~MyClass() {
std::cout << "MyClass destructed: " << value << std::endl;
}

void print() {
std::cout << "Value: " << value << std::endl;
}
};

int main() {
// 创建shared_ptr
std::shared_ptr<MyClass> ptr1(new MyClass(10));
auto ptr2 = std::make_shared<MyClass>(20);

// 访问成员
ptr1->print();
ptr2->print();

// 引用计数
std::cout << "ptr1 use_count: " << ptr1.use_count() << std::endl;

// 共享所有权
std::shared_ptr<MyClass> ptr3 = ptr1;
std::cout << "After sharing, ptr1 use_count: " << ptr1.use_count() << std::endl;
std::cout << "ptr3 use_count: " << ptr3.use_count() << std::endl;

// 重置
ptr1.reset();
std::cout << "After reset ptr1, ptr3 use_count: " << ptr3.use_count() << std::endl;

// 移动语义
std::shared_ptr<MyClass> ptr4 = std::move(ptr2);
std::cout << "After move, ptr2 is null: " << (!ptr2 ? "Yes" : "No") << std::endl;
std::cout << "ptr4 use_count: " << ptr4.use_count() << std::endl;

// 自动析构
{
auto ptr5 = std::make_shared<MyClass>(30);
std::cout << "ptr5 use_count: " << ptr5.use_count() << std::endl;
} // ptr5超出作用域,自动析构

return 0;
}

weak_ptr

weak_ptr是不增加引用计数的智能指针,用于观察shared_ptr管理的对象。

属性和方法:

方法描述参数返回值
lock获取shared_ptrshared_ptr对象
expired检查对象是否已销毁布尔值
use_count获取引用计数无符号整数
reset重置
swap交换另一个weak_ptr

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <memory>

class MyClass {
private:
int value;

public:
MyClass(int v) : value(v) {
std::cout << "MyClass constructed: " << value << std::endl;
}

~MyClass() {
std::cout << "MyClass destructed: " << value << std::endl;
}

void print() {
std::cout << "Value: " << value << std::endl;
}
};

int main() {
// 创建shared_ptr
std::shared_ptr<MyClass> sharedPtr = std::make_shared<MyClass>(10);

// 创建weak_ptr
std::weak_ptr<MyClass> weakPtr = sharedPtr;

// 检查引用计数
std::cout << "sharedPtr use_count: " << sharedPtr.use_count() << std::endl;
std::cout << "weakPtr use_count: " << weakPtr.use_count() << std::endl;

// 使用lock获取shared_ptr
if (auto lockedPtr = weakPtr.lock()) {
std::cout << "Object is alive, value: " << std::endl;
lockedPtr->print();
} else {
std::cout << "Object is expired" << std::endl;
}

// 检查是否过期
std::cout << "Before reset, weakPtr expired: " << weakPtr.expired() << std::endl;

// 重置shared_ptr,释放对象
sharedPtr.reset();

// 再次检查
std::cout << "After reset, weakPtr expired: " << weakPtr.expired() << std::endl;

// 尝试获取对象
if (auto lockedPtr = weakPtr.lock()) {
std::cout << "Object is alive, value: " << std::endl;
lockedPtr->print();
} else {
std::cout << "Object is expired" << std::endl;
}

return 0;
}

线程库

C++11引入了标准线程库,提供了跨平台的多线程支持。

thread类

属性和方法:

方法描述参数返回值
构造函数创建线程可调用对象, 参数线程对象
join等待线程结束
detach分离线程
joinable检查是否可连接布尔值
get_id获取线程ID线程ID
swap交换线程另一个线程
hardware_concurrency获取硬件并发度无符号整数

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <thread>
#include <vector>

void printHello() {
std::cout << "Hello from thread! Thread ID: " << std::this_thread::get_id() << std::endl;
}

void printNumber(int n) {
std::cout << "Number: " << n << " from thread! Thread ID: " << std::this_thread::get_id() << std::endl;
}

int main() {
// 创建线程
std::thread t1(printHello);
std::thread t2(printNumber, 42);

// 等待线程结束
std::cout << "Main thread waiting for t1..." << std::endl;
t1.join();
std::cout << "Main thread waiting for t2..." << std::endl;
t2.join();

// 创建多个线程
std::vector<std::thread> threads;
for (int i = 0; i < 5; ++i) {
threads.emplace_back(printNumber, i);
}

// 等待所有线程结束
std::cout << "Main thread waiting for all threads..." << std::endl;
for (auto& t : threads) {
t.join();
}

// 获取硬件并发度
std::cout << "Hardware concurrency: " << std::thread::hardware_concurrency() << std::endl;

return 0;
}

mutex类

属性和方法:

方法描述参数返回值
lock锁定互斥量
unlock解锁互斥量
try_lock尝试锁定互斥量布尔值

lock_guard类

属性和方法:

方法描述参数返回值
构造函数创建锁保护互斥量引用锁保护对象
析构函数自动解锁

C++20线程库新特性

jthread类(C++20+)

jthreadthread的扩展,提供了自动加入的功能,在析构时会自动调用join()

属性和方法:

方法描述参数返回值
构造函数创建线程可调用对象, 参数jthread对象
joinable检查是否可连接布尔值
join等待线程结束
detach分离线程
get_id获取线程ID线程ID
native_handle获取原生句柄原生句柄类型
request_stop请求停止
get_stop_token获取停止令牌stop_token

stop_token和stop_source类(C++20+)

提供了线程取消机制,用于请求线程停止执行。

属性和方法:

方法描述参数返回值
stop_sourcestop_requested检查是否请求停止布尔值
stop_sourcestop_possible检查是否可以停止布尔值
stop_sourcerequest_stop请求停止布尔值
stop_sourceget_token获取停止令牌stop_token
stop_tokenstop_requested检查是否请求停止布尔值
stop_tokenstop_possible检查是否可以停止布尔值

semaphore类(C++20+)

信号量同步原语,用于控制对共享资源的访问。

属性和方法:

方法描述参数返回值
构造函数创建信号量初始计数semaphore对象
acquire获取信号量
try_acquire尝试获取信号量布尔值
try_acquire_for在指定时间内尝试获取信号量时间段布尔值
try_acquire_until在指定时间点前尝试获取信号量时间点布尔值
release释放信号量释放数量(可选)

latch和barrier类(C++20+)

线程同步原语,用于等待一组线程完成操作。

属性和方法:

方法描述参数返回值
latch构造函数创建闩计数器latch对象
latchcount_down减少计数减少量(可选)
latchtry_wait检查计数是否为0布尔值
latchwait等待计数为0
latcharrive_and_wait减少计数并等待减少量(可选)
barrier构造函数创建屏障计数器, 完成函数(可选)barrier对象
barrierarrive_and_wait到达并等待
barrierarrive_and_drop到达并减少计数器

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>
#include <thread>
#include <syncstream>
#include <stop_token>
#include <semaphore>
#include <latch>
#include <barrier>

// 使用jthread和stop_token
void work_with_stop(std::stop_token st) {
int count = 0;
while (!st.stop_requested() && count < 100) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
count++;
}
std::osyncstream(std::cout) << "Work completed after " << count << " iterations\n";
}

// 使用semaphore
std::counting_semaphore<5> sem(3); // 最多3个线程同时访问

void semaphore_work(int id) {
sem.acquire();
std::osyncstream(std::cout) << "Thread " << id << " acquired semaphore\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::osyncstream(std::cout) << "Thread " << id << " releasing semaphore\n";
sem.release();
}

// 使用latch
void latch_work(std::latch& l, int id) {
std::osyncstream(std::cout) << "Thread " << id << " starting work\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100 * id));
std::osyncstream(std::cout) << "Thread " << id << " completed work\n";
l.count_down();
}

int main() {
std::cout << "=== Testing jthread and stop_token ===\n";
{
std::jthread t(work_with_stop);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
// jthread会自动join
}

std::cout << "\n=== Testing semaphore ===\n";
std::vector<std::thread> sem_threads;
for (int i = 0; i < 5; i++) {
sem_threads.emplace_back(semaphore_work, i);
}
for (auto& t : sem_threads) {
t.join();
}

std::cout << "\n=== Testing latch ===\n";
std::latch l(3);
std::vector<std::thread> latch_threads;
for (int i = 0; i < 3; i++) {
latch_threads.emplace_back(latch_work, std::ref(l), i);
}
std::cout << "Main thread waiting for latch\n";
l.wait();
std::cout << "Main thread proceeding after latch\n";
for (auto& t : latch_threads) {
t.join();
}

return 0;
}

时间库

C++11引入了标准时间库,提供了处理时间和日期的功能。

chrono库

属性和方法:

类/函数描述参数返回值
std::chrono::duration时间间隔计数值, 周期时间间隔对象
std::chrono::time_point时间点时钟, 时间间隔时间点对象
std::chrono::system_clock系统时钟时钟类型
std::chrono::steady_clock稳定时钟时钟类型
std::chrono::high_resolution_clock高分辨率时钟时钟类型
std::chrono::duration_cast转换时间间隔时间间隔转换后的时间间隔
std::chrono::time_point_cast转换时间点时间点转换后的时间点

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <chrono>
#include <thread>

int main() {
// 测量代码执行时间
auto start = std::chrono::high_resolution_clock::now();

// 模拟耗时操作
std::this_thread::sleep_for(std::chrono::milliseconds(100));

auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);

std::cout << "Elapsed time: " << duration.count() << " milliseconds" << std::endl;

// 使用时间间隔
std::chrono::seconds sec(1);
std::chrono::milliseconds ms = sec;
std::cout << "1 second = " << ms.count() << " milliseconds" << std::endl;

// 使用时间点
auto now = std::chrono::system_clock::now();
std::time_t now_time = std::chrono::system_clock::to_time_t(now);
std::cout << "Current time: " << std::ctime(&now_time);

return 0;
}

本地化库

本地化库提供了国际化和本地化支持,允许程序适应不同的语言和文化习惯。

locale类

属性和方法:

方法描述参数返回值
构造函数创建区域设置区域设置名称区域设置对象
name获取区域设置名称字符串
operator==比较区域设置另一个区域设置布尔值
operator!=比较区域设置另一个区域设置布尔值

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <locale>
#include <string>

int main() {
// 使用默认区域设置
std::locale loc;
std::cout << "Default locale: " << loc.name() << std::endl;

// 使用C区域设置
std::locale c_loc("C");
std::cout << "C locale: " << c_loc.name() << std::endl;

// 使用特定区域设置(如果可用)
try {
std::locale chinese_loc("zh_CN.UTF-8");
std::cout << "Chinese locale: " << chinese_loc.name() << std::endl;
} catch (const std::exception& e) {
std::cout << "Chinese locale not available: " << e.what() << std::endl;
}

// 使用区域设置进行数字格式化
std::locale fr_loc("fr_FR.UTF-8");
std::cout.imbue(fr_loc);
double value = 1234567.89;
std::cout << "Formatted number: " << value << std::endl;

return 0;
}

异常处理库

C++标准库提供了异常处理相关的类和函数。

异常类层次结构

  • std::exception - 所有标准异常的基类
    • std::bad_alloc - 内存分配失败
    • std::bad_cast - 类型转换失败
    • std::bad_typeid - 类型信息获取失败
    • std::bad_exception - 意外异常
    • std::logic_error - 逻辑错误
      • std::domain_error - 域错误
      • std::invalid_argument - 无效参数
      • std::length_error - 长度错误
      • std::out_of_range - 超出范围
    • std::runtime_error - 运行时错误
      • std::range_error - 范围错误
      • std::overflow_error - 溢出错误
      • std::underflow_error - 下溢错误

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <stdexcept>
#include <vector>

void divide(int a, int b) {
if (b == 0) {
throw std::invalid_argument("Division by zero");
}
std::cout << "Result: " << a / b << std::endl;
}

void accessVector(const std::vector<int>& vec, size_t index) {
if (index >= vec.size()) {
throw std::out_of_range("Index out of range");
}
std::cout << "Value at index " << index << ": " << vec[index] << std::endl;
}

int main() {
// 处理除零异常
try {
divide(10, 0);
} catch (const std::exception& e) {
std::cerr << "Exception caught: " << e.what() << std::endl;
}

// 处理向量越界异常
std::vector<int> vec = {1, 2, 3, 4, 5};
try {
accessVector(vec, 10);
} catch (const std::exception& e) {
std::cerr << "Exception caught: " << e.what() << std::endl;
}

// 处理内存分配异常
try {
while (true) {
new int[1000000000];
}
} catch (const std::bad_alloc& e) {
std::cerr << "Memory allocation failed: " << e.what() << std::endl;
}

return 0;
}

标准库最佳实践

1. 优先使用标准库组件

标准库组件经过了广泛的测试和优化,使用它们可以提高代码的可靠性和性能。

2. 理解组件的性能特性

不同的标准库组件有不同的性能特性,例如:

  • vector 提供随机访问,插入和删除操作在末尾是常数时间
  • list 提供双向遍历,任意位置的插入和删除操作是常数时间
  • map 提供有序的键值对,查找操作是对数时间
  • unordered_map 提供平均常数时间的查找操作

3. 使用智能指针管理内存

智能指针可以自动管理内存,避免内存泄漏和悬空指针的问题。

4. 合理使用异常

异常应该用于处理异常情况,而不是常规的控制流。

5. 了解标准库的局限性

标准库并不是万能的,对于某些特定的需求,可能需要使用第三方库或自定义实现。

6. 保持代码的可读性

使用标准库可以简化代码,但也需要注意保持代码的可读性,避免过度使用复杂的标准库特性。

7. 注意线程安全

标准库中的大多数组件不是线程安全的,在多线程环境中需要适当的同步措施。

总结

C++标准库是C++语言的重要组成部分,它提供了丰富的工具和组件,用于简化常见的编程任务。通过本文的介绍,我们了解了C++标准库的主要组成部分,包括:

  1. 核心语言支持库:提供基本类型和语言特性的支持
  2. 容器库:提供各种数据结构,如向量、列表、映射等
  3. 算法库:提供各种算法,如排序、查找、变换等
  4. 迭代器库:提供遍历容器元素的方法
  5. 数值库:提供数值计算相关的功能
  6. 输入/输出库:提供文件和流的输入输出操作
  7. 字符串库:提供字符串处理功能
  8. 时间库:提供时间和日期相关的功能
  9. 本地化库:提供国际化和本地化支持
  10. 异常处理库:提供异常处理相关的功能
  11. 智能指针库:提供内存管理的智能指针
  12. 线程库:提供多线程编程支持

通过合理使用标准库,我们可以提高开发效率,减少错误,编写更加可靠和可维护的代码。标准库的设计理念是”不要重复发明轮子”,通过使用标准库,我们可以专注于解决业务逻辑问题,而不是重复实现基础功能。

同时,我们也需要了解标准库的局限性,对于某些特定的需求,可能需要使用第三方库或自定义实现。在使用标准库时,我们应该注重代码的可读性和可维护性,避免过度使用复杂的标准库特性。

C++标准库是一个不断发展的工具集,随着C++标准的更新,标准库也在不断扩展和改进。作为C++开发者,我们应该持续关注标准库的发展,以便更好地利用它来提高我们的开发效率和代码质量。