第30章 C++基本库
C++标准库概述
C++标准库是C++语言的核心组成部分,它提供了一系列的工具和组件,用于简化常见的编程任务。标准库的设计理念是”不要重复发明轮子”,通过使用标准库,开发者可以避免编写重复的代码,提高开发效率和代码质量。
标准库的组成
C++标准库主要由以下几个部分组成:
- 核心语言支持库:提供基本类型和语言特性的支持
- 容器库:提供各种数据结构,如向量、列表、映射等
- 算法库:提供各种算法,如排序、查找、变换等
- 迭代器库:提供遍历容器元素的方法
- 数值库:提供数值计算相关的功能
- 输入/输出库:提供文件和流的输入输出操作
- 字符串库:提供字符串处理功能
- 时间库:提供时间和日期相关的功能
- 本地化库:提供国际化和本地化支持
- 异常处理库:提供异常处理相关的功能
- 智能指针库:提供内存管理的智能指针
- 线程库:提供多线程编程支持
标准库的使用
要使用标准库,需要包含相应的头文件,例如:
1 2 3 4 5 6
| #include <iostream> #include <vector> #include <algorithm> #include <string> #include <memory> #include <thread>
|
标准库中的组件都位于std命名空间中,因此在使用时需要加上std::前缀,或者使用using namespace std;来简化代码。
核心语言支持库
核心语言支持库提供了基本类型和语言特性的支持,包括:
- 基本类型 - 如
int、double、bool等 - 类型支持 - 如
std::size_t、std::nullptr_t等 - 类型特性 - 如
std::is_integral、std::is_floating_point等 - 动态内存管理 - 如
new、delete、std::allocator等 - 错误处理 - 如
std::exception、std::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; flag = false; std::cout << "Flag value: " << flag << std::endl; bool result = (5 > 3) && (2 < 4); std::cout << "Result: " << result << std::endl; return 0; }
|
C++23 打印库
C++23引入了std::print和std::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); std::println("Hello"); std::println("World"); 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}; 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预计将引入以下重要特性:
- 静态反射 - 编译时类型信息操作
- 模式匹配 - 基于值或类型的模式匹配
- 执行策略 - 统一的并行算法接口
- 网络库 - 标准网络编程支持
- 数学库增强 - 更多数学函数和算法
- 模块系统完善 - 进一步改进模块功能
这些特性将进一步提升C++的表达能力和开发效率,使C++成为更现代、更强大的编程语言。
容器库
容器类型
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <iostream>
int main() { int* ptr = nullptr; std::cout << "ptr is null: " << (ptr == nullptr) << std::endl; 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() { std::cout << add(1, 2) << std::endl; print(42); print(3.14); print("Hello"); std::cout << multiply(2, 3) << std::endl; std::cout << multiply(2.5, 3.5) << std::endl; 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>
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() { int arr[] = {1, 2, 3, 4, 5}; std::span<int> s1(arr); print_span(s1); std::vector<int> vec = {6, 7, 8, 9, 10}; std::span<int> s2(vec); print_span(s2); std::span<int> s3 = s1.subspan(1, 3); print_span(s3); 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; 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() { 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; 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() { 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() { 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() { 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() { 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() { 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() { 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; 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; 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}; 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; } 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; } int cnt = std::count(vec.begin(), vec.end(), 5); std::cout << "Count of 5: " << cnt << std::endl; cnt = std::count_if(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; }); std::cout << "Count of even numbers: " << cnt << std::endl; 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}; std::sort(vec.begin(), vec.end()); std::cout << "Sorted: " << std::endl; for (int num : vec) { std::cout << num << " "; } std::cout << std::endl; std::reverse(vec.begin(), vec.end()); std::cout << "Reversed: " << std::endl; for (int num : vec) { std::cout << num << " "; } std::cout << std::endl; 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; 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; 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()); std::copy(vec.begin(), vec.end(), dest.begin()); std::cout << "Copied: " << std::endl; for (int num : dest) { std::cout << num << " "; } std::cout << std::endl; 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; 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; 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; 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; 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}; int sum = std::accumulate(vec.begin(), vec.end(), 0); std::cout << "Sum: " << sum << std::endl; int product = std::accumulate(vec.begin(), vec.end(), 1, [](int a, int b) { return a * b; }); std::cout << "Product: " << product << std::endl; 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; 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; 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; }
|
字符串库
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; std::string s2 = std::format("{1}, {0}", "world", "Hello"); std::cout << s2 << std::endl; int x = 42; double y = 3.14; std::string s4 = std::format("x = {}, y = {:.2f}", x, y); std::cout << s4 << std::endl; char buffer[100]; std::format_to(std::begin(buffer), "The answer is {}", 42); std::cout << buffer << std::endl; size_t size = std::formatted_size("Hello, {}", "world"); std::cout << "Formatted size: " << size << std::endl; 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; } 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() { 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(); } 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() { 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; } return 0; }
|
weak_ptr
weak_ptr是不增加引用计数的智能指针,用于观察shared_ptr管理的对象。
属性和方法:
| 方法 | 描述 | 参数 | 返回值 |
|---|
lock | 获取shared_ptr | 无 | shared_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() { std::shared_ptr<MyClass> sharedPtr = std::make_shared<MyClass>(10); 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; 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; 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+)
jthread是thread的扩展,提供了自动加入的功能,在析构时会自动调用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_source | stop_requested | 检查是否请求停止 | 无 | 布尔值 |
stop_source | stop_possible | 检查是否可以停止 | 无 | 布尔值 |
stop_source | request_stop | 请求停止 | 无 | 布尔值 |
stop_source | get_token | 获取停止令牌 | 无 | stop_token |
stop_token | stop_requested | 检查是否请求停止 | 无 | 布尔值 |
stop_token | stop_possible | 检查是否可以停止 | 无 | 布尔值 |
semaphore类(C++20+)
信号量同步原语,用于控制对共享资源的访问。
属性和方法:
| 方法 | 描述 | 参数 | 返回值 |
|---|
| 构造函数 | 创建信号量 | 初始计数 | semaphore对象 |
acquire | 获取信号量 | 无 | 无 |
try_acquire | 尝试获取信号量 | 无 | 布尔值 |
try_acquire_for | 在指定时间内尝试获取信号量 | 时间段 | 布尔值 |
try_acquire_until | 在指定时间点前尝试获取信号量 | 时间点 | 布尔值 |
release | 释放信号量 | 释放数量(可选) | 无 |
latch和barrier类(C++20+)
线程同步原语,用于等待一组线程完成操作。
属性和方法:
| 类 | 方法 | 描述 | 参数 | 返回值 |
|---|
latch | 构造函数 | 创建闩 | 计数器 | latch对象 |
latch | count_down | 减少计数 | 减少量(可选) | 无 |
latch | try_wait | 检查计数是否为0 | 无 | 布尔值 |
latch | wait | 等待计数为0 | 无 | 无 |
latch | arrive_and_wait | 减少计数并等待 | 减少量(可选) | 无 |
barrier | 构造函数 | 创建屏障 | 计数器, 完成函数(可选) | barrier对象 |
barrier | arrive_and_wait | 到达并等待 | 无 | 无 |
barrier | arrive_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>
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"; }
std::counting_semaphore<5> sem(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(); }
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)); } 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; 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++标准库的主要组成部分,包括:
- 核心语言支持库:提供基本类型和语言特性的支持
- 容器库:提供各种数据结构,如向量、列表、映射等
- 算法库:提供各种算法,如排序、查找、变换等
- 迭代器库:提供遍历容器元素的方法
- 数值库:提供数值计算相关的功能
- 输入/输出库:提供文件和流的输入输出操作
- 字符串库:提供字符串处理功能
- 时间库:提供时间和日期相关的功能
- 本地化库:提供国际化和本地化支持
- 异常处理库:提供异常处理相关的功能
- 智能指针库:提供内存管理的智能指针
- 线程库:提供多线程编程支持
通过合理使用标准库,我们可以提高开发效率,减少错误,编写更加可靠和可维护的代码。标准库的设计理念是”不要重复发明轮子”,通过使用标准库,我们可以专注于解决业务逻辑问题,而不是重复实现基础功能。
同时,我们也需要了解标准库的局限性,对于某些特定的需求,可能需要使用第三方库或自定义实现。在使用标准库时,我们应该注重代码的可读性和可维护性,避免过度使用复杂的标准库特性。
C++标准库是一个不断发展的工具集,随着C++标准的更新,标准库也在不断扩展和改进。作为C++开发者,我们应该持续关注标准库的发展,以便更好地利用它来提高我们的开发效率和代码质量。