C++ 标准库头文件速查手册
📖 目录
第一章 输入输出流
1.1 <iostream> —— 最基础的输入输出
1.2 <iomanip> —— 控制输出格式(排版美化)
1.3 <fstream> —— 读写文件
1.4 <sstream> —— 字符串流(把字符串当"文件"操作)
第二章 容器
2.1 <vector> —— 动态数组(最常用!)
2.2 <list> —— 双向链表
2.3 <deque> —— 双端队列
2.4 <array> —— 固定大小数组(C++11)
2.5 <forward_list> —— 单向链表(C++11)
2.6 <stack> —— 栈
2.7 <queue> —— 队列
2.8 <priority_queue> —— 优先队列(堆)
2.9 <set> / <multiset> —— 有序集合
2.10 <map> / <multimap> —— 有序字典
2.11 <unordered_set> / <unordered_multiset> —— 无序集合(C++11)
2.12 <unordered_map> / <unordered_multimap> —— 无序字典(C++11)
第三章 算法
3.1 <algorithm> —— 通用算法
3.2 <numeric> —— 数值算法
第四章 字符串与字符处理
4.1 <string> —— 字符串(最常用!)
4.2 <string_view> —— 字符串视图(C++17)
4.3 <cctype> —— 字符判断与转换
4.4 <cstring> —— C 风格字符串操作
第五章 数学与数值
5.1 <cmath> —— 数学函数
5.2 <cstdlib> —— 随机数与通用工具
5.3 <random> —— 高质量随机数(C++11)
5.4 <complex> —— 复数
5.5 <limits> —— 类型极限值
5.6 <ratio> —— 编译期有理数(C++11)
第六章 时间与日期
6.1 <chrono> —— 现代时间库(C++11)
6.2 <ctime> —— C 风格时间
第七章 内存管理
7.1 <memory> —— 智能指针(C++11 重点!)
7.2 <new> —— 内存分配原语
第八章 多线程与并发(C++11 起)
8.1 <thread> —— 线程
8.2 <mutex> —— 互斥锁
8.3 <condition_variable> —— 条件变量
8.4 <future> —— 异步任务
8.5 <atomic> —— 原子操作
8.6 <shared_mutex> —— 读写锁(C++14/17)
第九章 函数对象与泛型编程
9.1 <functional> —— 函数包装与绑定
9.2 <type_traits> —— 类型特征(C++11)
9.3 <utility> —— 通用工具
9.4 <tuple> —— 元组(C++11)
9.5 <variant> —— 类型安全联合体(C++17)
9.6 <any> —— 任意类型容器(C++17)
9.7 <optional> —— 可选值(C++17)
第十章 异常处理
10.1 <exception> —— 异常基类
10.2 <stdexcept> —— 标准异常类
10.3 <system_error> —— 系统错误(C++11)
第十一章 类型信息(RTTI)
11.1 <typeinfo> —— 运行时类型识别
第十二章 正则表达式(C++11)
12.1 <regex> —— 正则表达式
第十三章 文件系统(C++17)
13.1 <filesystem> —— 文件系统操作
第十四章 C++20 新特性头文件
14.1 <format> —— 格式化(C++20)
14.2 <ranges> —— 范围库(C++20)
14.3 <span> —— 连续内存视图(C++20)
14.4 <concepts> —— 概念(C++20)
14.5 <compare> —— 三路比较(C++20)
第十六章 其他重要头文件
16.1 <cassert> —— 断言
16.2 <bitset> —— 位集
16.3 <initializer_list> —— 初始化列表(C++11)
16.4 <charconv> —— 低开销数值转换(C++17)
16.5 <numbers> —— 数学常量(C++20)
16.6 <source_location> —— 源码位置(C++20)
第十七章 头文件使用要点

C++ 标准库头文件速查手册

增强学习版 · 适合 iPhone 阅读

16 章·62 个小节·453 个代码示例
🚀 新手学习路线(按此顺序阅读)

⭐⭐⭐ 必须掌握 ⭐⭐ 重要 ⭐ 了解即可

  1. 第一阶段 1.1 iostream1.2 iomanip4.1 string (你人生的前 3 个头文件,先写 Hello World 和字符串处理)
  2. 第二阶段 · 容器核心 2.1 vector(最常用,90%场景用它)2.10 map / unordered_map2.9 set2.6 stack2.7 queue
  3. 第三阶段 · 算法 + 智能指针 3.1 algorithm(sort/查找/去重)7.1 memory(unique_ptr/shared_ptr)
  4. 第四阶段 · 进阶必备 1.3 fstream(文件)9.1 functional + lambda10.2 stdexcept(异常)9.4 tuple9.7 optional9.5 variant
  5. 第五阶段 · 按需学习 5章(数学) / 6章(时间) / 8章(多线程) / 12章(正则) / 13章(文件系统) / 14章(C++20)
🎯 容器选择决策表(看完就知道什么时候用什么)
容器特点你什么时候用它
vector动态数组·连续内存·尾部O(1)首选·90%场景不知道用啥就用它
string字符专属vector必须处理任何文本
array固定大小·栈分配大小已知且很小(≤32),性能极致
deque双端队列·头尾O(1)需要两端都 push/pop 的队列场景
list双向链表·任意插入O(1)几乎不用,现代CPU缓存机制下 vector 几乎总更快;除非你要在已知迭代器位置频繁插入
map红黑树·有序·O(log n)需要 key 排序、范围遍历时
unordered_map哈希·无序·平均O(1)首选字典不需要排序时用,比map快2-10倍
set / unordered_set去重集合查重、求交集/并集时使用
stack / queue容器适配器明确需要 LIFO(DFS) 或 FIFO(BFS) 语义时
priority_queue二叉堆·O(log n)Top-K、Dijkstra、任务调度
💡 新手最容易踩的坑
  1. 不要用 list 替代 vector —— 面试写链表可以,实际工程里 vector 永远是第一选择
  2. 不要用 map 当 unordered_map 用 —— 要排序才用 map,否则直接 unordered_map
  3. 不要 new/delete —— 用 unique_ptr / shared_ptr 代替,杜绝内存泄漏
  4. 不要用 char[] 存字符串 —— 用 std::string,安全不越界
  5. 不要手写 sort —— 用 std::sort,比你写的快且无 bug
第一章 输入输出流

1.1 <iostream> —— 最基础的输入输出C++

是什么

📚 iostream = input + output + stream,即"输入输出流"。

📚 可以把它想象成一根水管:数据像水一样在程序和你之间流动。

cin —— 标准输入(从键盘读数据)

🎯 类比:程序的"眼睛",看你在键盘上打了什么。

📌 说明:

• 用法:cin >> 变量;

// 完整可运行程序:演示 cin 的基本用法
#include <iostream>
#include <string>
using namespace std;

int main() {
    // 场景1:读取整数
    int age;
    cout << "请输入年龄:";
    cin >> age;                    // 输入 20,age 就变成 20
    cout << "你的年龄是:" << age << endl;

    // 场景2:读取字符串(遇空格停止)
    string name;
    cout << "请输入名字:";
    cin >> name;                   // 输入 Tom,name 变成 "Tom"
    cout << "你好," << name << "!" << endl;

    // 场景3:连续读取多个变量
    int a, b;
    cout << "请输入两个整数(用空格分隔):";
    cin >> a >> b;                 // 输入 3 5,a=3, b=5
    cout << a << " + " << b << " = " << a + b << endl;

    return 0;
}
⚠️ cin >> 遇到空格、回车、Tab 就会停下来,一次只读一个"词"。

1. 想读一整行(含空格)用 getline(cin, 变量)。

cout —— 标准输出(往屏幕显示数据)

🎯 类比:程序的"嘴巴",把信息说给你听。

📌 说明:

• 用法:cout << 要显示的内容;

// 完整可运行程序:演示 cout 的基本用法
#include <iostream>
#include <string>
using namespace std;

int main() {
    // 场景1:输出字符串
    cout << "Hello" << endl;             // 屏幕显示 Hello

    // 场景2:输出字符串和变量拼接
    cout << "年龄:" << 20 << endl;       // 屏幕显示 年龄:20

    // 场景3:输出变量
    int x = 5;
    cout << "x = " << x << endl;         // 屏幕显示 x = 5

    // 场景4:连续输出多个内容
    string name = "Tom";
    double score = 95.5;
    cout << name << " 的成绩是 " << score << " 分" << endl;
    // 屏幕显示:Tom 的成绩是 95.5 分

    return 0;
}

💡 小技巧:用 << 可以连续拼接多个内容,就像说话一样一句接一句,

想输出什么就往后面接什么,非常灵活。

cerr —— 标准错误输出

🎯 一句话理解:cerr 是 cout 的"双胞胎兄弟",专门负责报错误。

📌 和 cout 的区别:

• cout 会"攒一批再输出"(有缓冲区,效率高)

• cerr 是"有话立刻说"(不缓冲,立即输出,确保错误信息能及时看到)

🤔 什么时候用?

• 程序出错了,要提示用户 → 用 cerr

• 正常输出结果 → 用 cout

• 初学者先记住有这个东西,写项目时自然会用到

#include <iostream>
using namespace std;
int main() {
    // 场景:模拟文件打开失败,用 cerr 输出错误
    // cerr 不缓冲,错误信息会立即显示,不会丢失
    cerr << "❌ 错误:文件打开失败!" << endl;
    cerr << "   请检查文件路径是否正确" << endl;
    return 0;
}

clog —— 标准日志输出

🎯 一句话理解:clog 是 cerr 的"缓冲版",专门用来写日志。

📌 和 cerr 的区别:

• cerr 不缓冲,立即输出(适合紧急错误)

• clog 有缓冲,攒一批再输出(适合普通日志,效率更高)

🤔 什么时候用?

• 记录程序运行日志(如"程序启动了""用户登录了")→ 用 clog

• 初学者基本用不到,了解即可

#include <iostream>
using namespace std;
int main() {
    // 场景:记录程序运行日志
    // clog 有缓冲,适合大量日志输出,效率更高
    clog << "[INFO] 程序启动成功" << endl;
    clog << "[INFO] 加载配置文件完成" << endl;
    clog << "[INFO] 等待用户操作..." << endl;
    return 0;
}

endl —— 换行并刷新

🎯 一句话理解:endl = 换行 + 强制刷新,相当于"按回车并立刻显示"。

🏠 生活类比:就像发微信消息,endl 是"打字 + 立刻发送",

而 '\n' 只是"打字换行",内容可能还在输入框里没发出去。

#include <iostream>
using namespace std;
int main() {
    // endl:换行 + 刷新(内容立刻显示)
    cout << "第一行" << endl;
    cout << "第二行" << endl;
    // '\n':只换行,不刷新(效率更高)
    cout << "第三行\n";
    cout << "第四行\n";
    return 0;
}

⚠️ 注意:

• endl 不只是换行,还会"刷新缓冲区"(强制立刻显示)

• 大量输出时频繁用 endl 会稍慢,只想换行推荐用 '\n'

• 比如循环输出10000行,用 '\n' 比 endl 快不少

flush —— 刷新缓冲区

🎯 一句话理解:flush 是"催一下",让缓冲区里的内容立刻显示出来。

📌 什么时候用?

• 一般不需要手动调用,endl 会自动刷新

• 特殊场景:输出提示后不换行,但想立刻让用户看到(如"正在加载...")

• 比如进度条、等待提示等场景

#include <iostream>
#include <ctime>
using namespace std;
int main() {
    cout << "正在加载...";
    cout.flush();  // 强制立刻显示,不等换行
    // 模拟耗时操作
    // ... 做一些耗时操作 ...
    cout << "完成!" << endl;
    return 0;
}
#include <iostream>
#include <string>
using namespace std;
int main() {
    cout << "请输入你的名字:";
    string name;
    cin >> name;
    cout << "你好," << name << "!" << endl;
    return 0;
}

1.2 <iomanip> —— 控制输出格式(排版美化)C++

是什么

📚 iomanip = input output manipulators,专门控制 cout 输出的样子。

📚 类比:Word 里的排版工具,控制文字怎么显示。

setw(n) —— 设置输出宽度

🎯 让下一个输出至少占 n 个字符位置,不够用空格补。

📌 说明:

• 只对"下一个"输出有效。

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    // 设置输出宽度为5,右对齐(默认)
    cout << setw(5) << 12;        // 输出 "   12"(前3空格,共5位)
    cout << endl;
    // setw 只对下一个输出有效
    cout << setw(5) << 12 << 34;  // 输出 "   1234"(34没有宽度)
    cout << endl;
    return 0;
}

setprecision(n) —— 设置浮点数精度

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    double pi = 3.1415926;
    // 单独用:控制有效数字总位数
    cout << setprecision(3) << pi << endl;   // 3.14(3位有效数字)
    // 配合 fixed:控制小数点后位数
    cout << fixed << setprecision(2) << pi << endl;  // 3.14
    return 0;
}
⚠️ 单独用 setprecision 控制"有效数字"总位数;配合 fixed 才控制"小数点后"位数。

setfill(c) —— 设置填充字符

setw 宽度有多余空间时用什么字符填充(默认空格)。

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    // 用 * 填充
    cout << setfill('*') << setw(5) << 12 << endl;   // 输出 "***12"
    // 恢复默认空格填充
    cout << setfill(' ') << setw(5) << 12 << endl;   // 输出 "   12"
    return 0;
}

setbase(n) —— 设置进制

🎯 n 只能是 8、10、16。

💡 小贴士:

• 也可以直接用 hex / oct / dec。

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    cout << setbase(16) << 255 << endl;   // 输出 ff(十六进制)
    cout << setbase(8) << 255 << endl;    // 输出 377(八进制)
    cout << setbase(10) << 255 << endl;   // 输出 255(十进制)
    // 也可以直接用 hex/oct/dec
    cout << hex << 255 << endl;           // ff
    return 0;
}

left / right / internal —— 对齐方式

🎯 left 左对齐 | right 右对齐(默认) | internal 符号左对齐数字右对齐

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    cout << left  << setw(5) << 12 << endl;  // "12   "(左对齐)
    cout << right << setw(5) << 12 << endl;  // "   12"(右对齐)
    cout << internal << setw(5) << -12 << endl; // "-  12"
    return 0;
}

fixed / scientific —— 浮点数显示方式

🎯 fixed 普通小数形式 | scientific 科学计数法

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    cout << fixed      << 0.00123 << endl;   // 0.001230
    cout << scientific << 0.00123 << endl;   // 1.230000e-03
    return 0;
}

boolalpha / noboolalpha —— 布尔值显示

🎯 boolalpha 显示 true/false | noboolalpha 显示 1/0(默认)

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    cout << boolalpha << true << endl;    // 输出 true
    cout << noboolalpha << true << endl;  // 输出 1
    return 0;
}

showbase / noshowbase —— 显示进制前缀

十六进制前加 0x,八进制前加 0。

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    cout << showbase << hex << 255 << endl;   // 输出 0xff
    cout << noshowbase << hex << 255 << endl; // 输出 ff
    return 0;
}

showpos / noshowpos —— 正数前显示 + 号

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    cout << showpos << 5 << endl;    // 输出 +5
    cout << noshowpos << 5 << endl;  // 输出 5
    return 0;
}

uppercase / nouppercase —— 十六进制字母大写

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    cout << uppercase << hex << 255 << endl;   // 输出 FF
    cout << nouppercase << hex << 255 << endl; // 输出 ff
    return 0;
}

resetiosflags —— 重置格式标志,恢复默认

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    cout << hex << 255 << endl;        // ff
    cout << resetiosflags(ios::basefield) << dec << 255 << endl;  // 255
    return 0;
}
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    cout << "商品价格表" << endl;
    cout << left  << setw(10) << "苹果"
         << right << setw(8) << fixed << setprecision(2) << 9.5  << "元" << endl;
    cout << left  << setw(10) << "香蕉"
         << right << setw(8) << fixed << setprecision(2) << 3.2  << "元" << endl;
    return 0;
}
/* 输出:
商品价格表
苹果          9.50元
香蕉          3.20元  */

1.3 <fstream> —— 读写文件C++

是什么

📚 fstream = file stream,文件流。

📚 让程序能读写硬盘上的文件。

📚 类比:cin/cout 和键盘屏幕对话,fstream 和文件对话。

ifstream —— 输入文件流(从文件读)

类比:打开一本书来"读"。

#include <fstream>
#include <iostream>
using namespace std;
int main() {
    ifstream fin("data.txt");     // 打开文件用于读取
    if (!fin) {                   // 判断是否成功打开
        cout << "打开失败" << endl;
        return 1;
    }
    int x;
    fin >> x;                     // 从文件读一个整数
    cout << "读取到:" << x << endl;
    fin.close();                  // 读完关闭
    return 0;
}

ofstream —— 输出文件流(往文件写)

类比:拿笔往本子上"写"。

#include <fstream>
using namespace std;
int main() {
    ofstream fout("output.txt");  // 不存在则创建
    fout << "Hello" << endl;
    fout << "World" << endl;
    fout.close();
    return 0;
}
⚠️ 默认会清空文件原有内容!想追加用 ios::app 模式。

fstream —— 同时读写文件

既可以读也可以写,需指定打开模式。

#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
    fstream fs("data.txt", ios::in | ios::out);  // 读写模式
    fs << "写入内容";
    fs.seekg(0);  // 指针移回开头
    string s;
    fs >> s;      // 读出来
    cout << "读出:" << s << endl;
    fs.close();
    return 0;
}

打开模式(构造函数或 open() 中指定,可组合用 |)

模式 说明

ios::in 读模式(ifstream 默认)

ios::out 写模式(ofstream 默认,清空原内容)

ios::app 追加模式(末尾添加,不清空)

ios::trunc 截断模式(清空原内容)

ios::binary 二进制模式(默认文本模式)

读文件的三种方式

方式一:>> 逐个读(遇空格/换行停止)

#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
    ifstream fin("data.txt");
    string word;
    while (fin >> word) {       // 逐个词读取
        cout << word << endl;
    }
    fin.close();
    return 0;
}

方式二:getline 逐行读(可读空格)

#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
    ifstream fin("data.txt");
    string line;
    while (getline(fin, line)) { // 逐行读取
        cout << line << endl;
    }
    fin.close();
    return 0;
}

方式三:get() 逐个字符读

#include <fstream>
#include <iostream>
using namespace std;
int main() {
    ifstream fin("data.txt");
    char c;
    while (fin.get(c)) {         // 逐个字符读取
        cout << c;
    }
    fin.close();
    return 0;
}
#include <fstream>
using namespace std;
int main() {
    // 追加写入日记(ios::app 模式,不清空原有内容)
    ofstream fout("日记.txt", ios::app);
    fout << "2026年8月12日 晴" << endl;
    fout << "今天学了C++文件操作。" << endl;
    fout.close();
    return 0;
}

1.4 <sstream> —— 字符串流(把字符串当"文件"操作)C++

是什么

📚 sstream = string stream,把字符串当成"虚拟文件"来读写。

📚 类比:内存里的一块小黑板,可以往上写也可以从上面读。

istringstream —— 从字符串读取

把字符串拆开,提取各种类型数据。

#include <sstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
    string data = "Tom 20 95.5";
    istringstream iss(data);
    string name;
    int age;
    double score;
    iss >> name >> age >> score;   // 自动按空格拆分并转换类型
    cout << name << " " << age << " " << score << endl;
    return 0;
}

ostringstream —— 往字符串写入

把各种数据拼接到一个字符串里。

#include <sstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
    ostringstream oss;
    oss << "姓名:" << "Tom" << ",年龄:" << 20;
    string result = oss.str();     // 取出拼接好的字符串
    cout << result << endl;
    return 0;
}

stringstream —— 既可读又可写(上面两者的结合)

#include <sstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
    stringstream ss;
    ss << "年龄:" << 20;        // 写入
    string s = ss.str();         // 取出 "年龄:20"
    cout << s << endl;
    ss.clear();                  // 清空状态以便复用
    ss.str("");                  // 清空内容
    return 0;
}

常见用途

- 字符串转数字:istringstream iss("123"); int x; iss >> x;

- 数字转字符串:ostringstream oss; oss << 123; string s = oss.str();

- 拆分一行数据(如处理 CSV)

💡 C++11 以后有更简单的 to_string() 和 stoi(),但 sstream 更灵活。
第二章 容器

容器是什么

容器就是装数据的"盒子"。不同盒子有不同特点:

有的像数组(随机访问快),有的像链表(插入快),有的像队列(先进先出)。

选对容器,程序又快又好写。

2.1 <vector> —— 动态数组(最常用!)C++

是什么

📚 vector 是"会自动变长的数组"。

📚 普通数组大小固定,vector 可随时加元素,自动扩容。

📚 类比:可伸缩的收纳盒,东西多了自动变大。

vector<T> —— 动态数组类模板

🎯 T 是元素类型:vector<int> 装整数,vector<string> 装字符串。

创建方式

vector<int> v1; // 空数组

vector<int> v2(5); // 5个元素,默认都是0

vector<int> v3(5, 10); // 5个元素,都是10

vector<int> v4 = {1,2,3,4}; // 初始化列表(C++11)

常用方法一览(每个方法附完整示例)

push_back(x) —— 末尾添加元素,O(1)均摊

#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {10, 20, 30};
    v.push_back(40);  // 末尾添加40
    // v 变成 {10,20,30,40}
    for (int x : v) cout << x << " ";
    cout << endl;
    return 0;
}

pop_back() —— 删除末尾元素,O(1)

#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {10, 20, 30};
    v.pop_back();     // 删除末尾元素
    // v 变成 {10,20}
    for (int x : v) cout << x << " ";
    cout << endl;
    return 0;
}

size() —— 返回元素个数,O(1)

#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {10, 20, 30};
    int n = v.size(); // n = 3
    cout << "元素个数:" << n << endl;
    return 0;
}

empty() —— 是否为空,O(1)

#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v;
    if (v.empty()) cout << "空" << endl;
    v.push_back(1);
    if (!v.empty()) cout << "非空" << endl;
    return 0;
}

clear() —— 清空所有元素,O(n)

#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {10, 20, 30};
    v.clear();        // 清空所有元素
    // v 变成空,size() = 0
    cout << "清空后元素个数:" << v.size() << endl;
    return 0;
}

v[i] / at(i) —— 访问第 i 个元素,O(1)

#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {10, 20, 30};
    int x = v[0];     // x = 10
    int y = v.at(1);  // y = 20,越界会抛异常
    cout << "v[0]=" << x << ", v.at(1)=" << y << endl;
    return 0;
}

front() / back() —— 首/尾元素,O(1)

#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {10, 20, 30};
    int f = v.front(); // f = 10
    int b = v.back();  // b = 30
    cout << "首元素:" << f << ",尾元素:" << b << endl;
    return 0;
}

insert(pos, x) —— 指定位置插入,O(n)

#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {10, 20, 30};
    v.insert(v.begin() + 1, 15);  // 在第1个位置插入15
    // v 变成 {10,15,20,30}
    for (int x : v) cout << x << " ";
    cout << endl;
    return 0;
}

erase(pos) —— 删除指定位置元素,O(n)

#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {10, 20, 30};
    v.erase(v.begin() + 1);  // 删除第1个元素
    // v 变成 {10,30}
    for (int x : v) cout << x << " ";
    cout << endl;
    return 0;
}

resize(n) —— 改变大小,O(n)

#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {10, 20, 30};
    v.resize(5);   // 变成5个元素,新增的默认0
    // v = {10,20,30,0,0}
    v.resize(2);   // 变成2个元素,多余的删掉
    // v = {10,20}
    for (int x : v) cout << x << " ";
    cout << endl;
    return 0;
}

reserve(n) —— 预留空间(不改变 size),O(1)

#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v;
    v.reserve(100);  // 提前分配100个空间,避免频繁扩容
    cout << "容量:" << v.capacity() << ",元素个数:" << v.size() << endl;
    return 0;
}

begin() / end() —— 迭代器(指向开头/结尾后一位),O(1)

#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {10, 20, 30};
    // 用迭代器遍历
    for (auto it = v.begin(); it != v.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    return 0;
}
⚠️ [] 越界访问是未定义行为,可能崩溃;at() 越界会抛异常,更安全。

1. 下标从 0 开始!

2. 三种遍历方式 // 方式一:下标遍历 [示例] #include <vector> #include <iostream> using namespace std; int main() { vector<int> v = {10, 20, 30}; for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; return 0; } // 方式二:范围 for(C++11,推荐) [示例] #include <vector> #include <iostream> using namespace std; int main() { vector<int> v = {10, 20, 30}; for (int x : v) { cout << x << " "; } cout << endl; return 0; } // 方式三:迭代器 [示例] #include <vector> #include <iostream> using namespace std; int main() { vector<int> v = {10, 20, 30}; for (auto it = v.begin(); it != v.end(); ++it) { cout << *it << " "; } cout << endl; return 0; } 特点 优点:随机访问快,尾部增删快,内存连续 缺点:中间增删慢(要挪动元素),扩容有性能开销 场景:大多数情况都用 vector,是默认首选

2.2 <list> —— 双向链表C++

是什么

📚 双向链表,每个元素存了"上一个"和"下一个"元素的地址。

📚 类比:一串手拉手的人,每个人都知道左右是谁。

📚 找第N个人要从第一个开始数。

和 vector 的核心区别

vector:元素内存紧挨着,可用 [] 直接跳到第N个。

list: 元素分散在内存,只能通过指针一个个找,不能用 []。

常用方法(每个方法附完整示例)

push_front(x) / push_back(x) —— 头/尾插入,O(1)

#include <list>
#include <iostream>
using namespace std;
int main() {
    list<int> lst = {10, 20, 30};
    lst.push_front(5);   // 头部插入5
    lst.push_back(40);   // 尾部插入40
    // lst = {5,10,20,30,40}
    for (int x : lst) cout << x << " ";
    cout << endl;
    return 0;
}

pop_front() / pop_back() —— 头/尾删除

#include <list>
#include <iostream>
using namespace std;
int main() {
    list<int> lst = {10, 20, 30};
    lst.pop_front();     // 删除头部
    lst.pop_back();      // 删除尾部
    // lst = {20}
    for (int x : lst) cout << x << " ";
    cout << endl;
    return 0;
}

insert(pos, x) —— 迭代器位置插入,O(1)

#include <list>
#include <iostream>
using namespace std;
int main() {
    list<int> lst = {10, 20, 30};
    lst.insert(++lst.begin(), 15);  // 在第2个位置插入15
    // lst = {10,15,20,30}
    for (int x : lst) cout << x << " ";
    cout << endl;
    return 0;
}

erase(pos) —— 删除迭代器指向元素,O(1)

#include <list>
#include <iostream>
using namespace std;
int main() {
    list<int> lst = {10, 20, 30};
    lst.erase(lst.begin());  // 删除第一个元素
    // lst = {20,30}
    for (int x : lst) cout << x << " ";
    cout << endl;
    return 0;
}

sort() —— 排序(list 自带,不能用 std::sort)

#include <list>
#include <iostream>
using namespace std;
int main() {
    list<int> lst = {30, 10, 20};
    lst.sort();          // 从小到大排序
    // lst = {10,20,30}
    for (int x : lst) cout << x << " ";
    cout << endl;
    return 0;
}

reverse() —— 反转

#include <list>
#include <iostream>
using namespace std;
int main() {
    list<int> lst = {10, 20, 30};
    lst.reverse();       // 反转
    // lst = {30,20,10}
    for (int x : lst) cout << x << " ";
    cout << endl;
    return 0;
}

merge(other) —— 合并两个已排序 list

#include <list>
#include <iostream>
using namespace std;
int main() {
    list<int> a = {1, 3}, b = {2, 4};
    a.merge(b);          // 合并两个已排序list
    // a = {1,2,3,4},b 变空
    for (int x : a) cout << x << " ";
    cout << endl;
    return 0;
}

unique() —— 去除相邻重复元素

#include <list>
#include <iostream>
using namespace std;
int main() {
    list<int> c = {1, 1, 2, 2, 3};
    c.unique();          // 去除相邻重复
    // c = {1,2,3}
    for (int x : c) cout << x << " ";
    cout << endl;
    return 0;
}

remove(x) —— 删除所有等于 x 的元素

#include <list>
#include <iostream>
using namespace std;
int main() {
    list<int> lst = {10, 20, 30, 20};
    lst.remove(20);      // 删除所有20
    // lst = {10,30}
    for (int x : lst) cout << x << " ";
    cout << endl;
    return 0;
}

特点

优点:任意位置增删快(O(1)),不需挪动元素

缺点:不能随机访问,内存开销大(每个元素多存两个指针)

场景:需要频繁在中间增删元素时

2.3 <deque> —— 双端队列C++

是什么

📚 deque = double-ended queue,头尾都可快速增删,同时支持随机访问。

📚 类比:两头都能开口的管子,从哪头放取都很快。

常用方法(每个方法附完整示例)

push_front(x) / push_back(x) —— 头尾插入,O(1)

#include <deque>
#include <iostream>
using namespace std;
int main() {
    deque<int> dq = {10, 20, 30};
    dq.push_front(5);   // 头部插入
    dq.push_back(40);   // 尾部插入
    // dq = {5,10,20,30,40}
    for (int x : dq) cout << x << " ";
    cout << endl;
    return 0;
}

pop_front() / pop_back() —— 头尾删除

#include <deque>
#include <iostream>
using namespace std;
int main() {
    deque<int> dq = {10, 20, 30};
    dq.pop_front();     // 删除头部
    dq.pop_back();      // 删除尾部
    // dq = {20}
    for (int x : dq) cout << x << " ";
    cout << endl;
    return 0;
}

[] / at() —— 随机访问,O(1)

#include <deque>
#include <iostream>
using namespace std;
int main() {
    deque<int> dq = {10, 20, 30};
    int x = dq[0];      // x = 10
    int y = dq.at(1);   // y = 20,越界抛异常
    cout << "dq[0]=" << x << ", dq.at(1)=" << y << endl;
    return 0;
}

front() / back() —— 首尾元素

#include <deque>
#include <iostream>
using namespace std;
int main() {
    deque<int> dq = {10, 20, 30};
    int f = dq.front(); // 10
    int b = dq.back();  // 30
    cout << "首元素:" << f << ",尾元素:" << b << endl;
    return 0;
}

size() / empty() / clear()

#include <deque>
#include <iostream>
using namespace std;
int main() {
    deque<int> dq = {10, 20, 30};
    int n = dq.size();  // 3
    cout << "元素个数:" << n << endl;
    if (!dq.empty()) cout << "非空" << endl;
    dq.clear();         // 清空
    cout << "清空后元素个数:" << dq.size() << endl;
    return 0;
}

特点

优点:头尾增删都快,支持随机访问

缺点:中间增删慢,内存布局比 vector 复杂

场景:需要头尾都操作时(队列、滑动窗口)

2.4 <array> —— 固定大小数组(C++11)C++

是什么

📚 array<T, N> 对原生数组的封装,大小编译时确定(N是常量)。

📚 类比:普通数组,但包装得更安全、更方便。

和原生数组对比

int arr[5]; // 原生数组

array<int, 5> arr; // C++ array

优点

- 知道自己大小:arr.size() 直接返回 5

- at() 安全访问(越界抛异常)

- 可直接赋值和比较:arr1 = arr2; if (arr1 == arr2)

- 作为函数参数不会退化成指针

常用方法(每个方法附完整示例)

size() / empty()

#include <array>
#include <iostream>
using namespace std;
int main() {
    array<int, 3> arr = {10, 20, 30};
    int n = arr.size();  // 3(编译期常量)
    cout << "元素个数:" << n << endl;
    if (!arr.empty()) cout << "非空" << endl;  // 永远非空,因为大小固定
    return 0;
}

[] / at() / front() / back()

#include <array>
#include <iostream>
using namespace std;
int main() {
    array<int, 3> arr = {10, 20, 30};
    int x = arr[0];      // 10
    int y = arr.at(1);   // 20,越界抛异常
    int f = arr.front(); // 10
    int b = arr.back();  // 30
    cout << x << " " << y << " " << f << " " << b << endl;
    return 0;
}

data() —— 底层原生数组指针

#include <array>
#include <iostream>
using namespace std;
int main() {
    array<int, 3> arr = {10, 20, 30};
    int* p = arr.data(); // p 指向第一个元素
    cout << p[0] << endl;  // 10
    return 0;
}

fill(x) —— 所有元素填成 x

#include <array>
#include <iostream>
using namespace std;
int main() {
    array<int, 3> arr = {10, 20, 30};
    arr.fill(0);         // 所有元素填0
    // arr = {0,0,0}
    for (int x : arr) cout << x << " ";
    cout << endl;
    return 0;
}

swap(other) —— 交换两个 array

#include <array>
#include <iostream>
using namespace std;
int main() {
    array<int,3> a1={1,2,3}, a2={4,5,6};
    a1.swap(a2);         // 交换
    // a1={4,5,6}, a2={1,2,3}
    for (int x : a1) cout << x << " ";
    cout << endl;
    return 0;
}

场景:大小固定且较小的数组(一周7天、一副牌54张),比 vector 更轻量。

2.5 <forward_list> —— 单向链表(C++11)C++

是什么

📚 单向链表,每个元素只存"下一个"的地址(list 存上下两个)。

📚 类比:一列火车,每节只知道后面那节,不知道前面。

📚 只能从头往尾遍历。

和 list 的区别

- 比 list 省内存(少存一个指针)

- 只能从前向后遍历,没有反向迭代器

- 没有 size() 方法

- 插入删除在"某个位置之后"操作:insert_after / erase_after

常用方法(每个方法附完整示例)

push_front(x) / pop_front() —— 头部增删

#include <forward_list>
#include <iostream>
using namespace std;
int main() {
    forward_list<int> fl = {10, 20, 30};
    fl.push_front(5);   // 头部插入
    // fl = {5,10,20,30}
    fl.pop_front();     // 删除头部
    // fl = {10,20,30}
    for (int x : fl) cout << x << " ";
    cout << endl;
    return 0;
}

insert_after(pos, x) —— pos 之后插入

#include <forward_list>
#include <iostream>
using namespace std;
int main() {
    forward_list<int> fl = {10, 20, 30};
    fl.insert_after(fl.begin(), 15);  // 第一个元素后插入15
    // fl = {10,15,20,30}
    for (int x : fl) cout << x << " ";
    cout << endl;
    return 0;
}

erase_after(pos) —— 删除 pos 之后的元素

#include <forward_list>
#include <iostream>
using namespace std;
int main() {
    forward_list<int> fl = {10, 20, 30};
    fl.erase_after(fl.begin());  // 删除第一个元素之后的元素
    // fl = {10,30}
    for (int x : fl) cout << x << " ";
    cout << endl;
    return 0;
}

sort() / reverse() / merge() / unique() / remove()

#include <forward_list>
#include <iostream>
using namespace std;
int main() {
    forward_list<int> fl = {30, 10, 20, 10};
    fl.sort();           // 排序:{10,10,20,30}
    fl.unique();         // 去相邻重复:{10,20,30}
    fl.reverse();        // 反转:{30,20,10}
    fl.remove(20);       // 删除所有20:{30,10}
    for (int x : fl) cout << x << " ";
    cout << endl;
    return 0;
}

场景:对内存极敏感且只需单向遍历时。初学者一般用 list 就够。

2.6 <stack> —— 栈C++

是什么

📚 栈,遵循"后进先出"(LIFO = Last In First Out)。

📚 类比:一摞盘子,最后放上去的最先被拿走。

📚 只能操作"栈顶"。

常用方法(每个方法附完整示例)

push(x) —— 把 x 压入栈顶

#include <stack>
#include <iostream>
using namespace std;
int main() {
    stack<int> s;
    s.push(1);
    s.push(2);  // 栈里 [1,2],2在栈顶
    cout << "栈顶:" << s.top() << endl;
    return 0;
}

pop() —— 弹出栈顶元素(不返回值!)

#include <stack>
#include <iostream>
using namespace std;
int main() {
    stack<int> s;
    s.push(1);
    s.push(2);
    s.pop();               // 删掉2,栈里只剩 [1]
    cout << "栈顶:" << s.top() << endl;
    return 0;
}

top() —— 查看栈顶元素(不删除)

#include <stack>
#include <iostream>
using namespace std;
int main() {
    stack<int> s;
    s.push(1);
    int x = s.top();       // x = 1
    cout << "栈顶:" << x << endl;
    return 0;
}

size() —— 元素个数

#include <stack>
#include <iostream>
using namespace std;
int main() {
    stack<int> s;
    s.push(1);
    s.push(2);
    int n = s.size();      // n = 2
    cout << "元素个数:" << n << endl;
    return 0;
}

empty() —— 是否为空

#include <stack>
#include <iostream>
using namespace std;
int main() {
    stack<int> s;
    if (s.empty()) cout << "栈空" << endl;
    s.push(1);
    if (!s.empty()) cout << "栈非空" << endl;
    return 0;
}
#include <stack>
#include <iostream>
using namespace std;
int main() {
    stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
    cout << s.top() << endl;   // 输出 3
    s.pop();
    cout << s.top() << endl;   // 输出 2
    return 0;
}

场景:函数调用栈、括号匹配、表达式求值、DFS、撤销操作

2.7 <queue> —— 队列C++

是什么

📚 队列,遵循"先进先出"(FIFO = First In First Out)。

📚 类比:排队买奶茶,先来的先买到。

📚 队尾加元素,队头删元素。

常用方法(每个方法附完整示例)

push(x) —— 队尾加入元素

#include <queue>
#include <iostream>
using namespace std;
int main() {
    queue<int> q;
    q.push(1);
    q.push(2);  // 队列 [1,2],1在队头
    cout << "队头:" << q.front() << ",队尾:" << q.back() << endl;
    return 0;
}

pop() —— 队头删除元素

#include <queue>
#include <iostream>
using namespace std;
int main() {
    queue<int> q;
    q.push(1);
    q.push(2);
    q.pop();               // 删掉1,队列只剩 [2]
    cout << "队头:" << q.front() << endl;
    return 0;
}

front() —— 查看队头元素

#include <queue>
#include <iostream>
using namespace std;
int main() {
    queue<int> q;
    q.push(1);
    q.push(2);
    int f = q.front();     // f = 1
    cout << "队头:" << f << endl;
    return 0;
}

back() —— 查看队尾元素

#include <queue>
#include <iostream>
using namespace std;
int main() {
    queue<int> q;
    q.push(1);
    q.push(2);
    int b = q.back();      // b = 2
    cout << "队尾:" << b << endl;
    return 0;
}

size() / empty()

#include <queue>
#include <iostream>
using namespace std;
int main() {
    queue<int> q;
    q.push(1);
    int n = q.size();      // 1
    cout << "元素个数:" << n << endl;
    if (!q.empty()) cout << "队列非空" << endl;
    return 0;
}

场景:任务排队、BFS、消息队列、缓冲区

2.8 <priority_queue> —— 优先队列(堆)C++

是什么

📚 优先队列,每次取出的都是"优先级最高"的元素。

📚 默认大顶堆(最大的在最前)。

📚 类比:急诊室,病情最重的人优先看病,不管谁先来。

常用方法(每个方法附完整示例)

push(x) —— 加入元素

#include <queue>
#include <iostream>
using namespace std;
int main() {
    priority_queue<int> pq;
    pq.push(3);
    pq.push(1);
    pq.push(2);  // 内部自动排序,最大的在堆顶
    cout << "堆顶:" << pq.top() << endl;  // 3
    return 0;
}

pop() —— 删除优先级最高的元素

#include <queue>
#include <iostream>
using namespace std;
int main() {
    priority_queue<int> pq;
    pq.push(3);
    pq.push(1);
    pq.push(2);
    pq.pop();               // 删掉最大的3
    cout << "堆顶:" << pq.top() << endl;  // 2
    return 0;
}

top() —— 查看优先级最高的元素

#include <queue>
#include <iostream>
using namespace std;
int main() {
    priority_queue<int> pq;
    pq.push(3);
    pq.push(1);
    pq.push(2);
    int x = pq.top();       // x = 3(最大的)
    cout << "堆顶:" << x << endl;
    return 0;
}

size() / empty()

#include <queue>
#include <iostream>
using namespace std;
int main() {
    priority_queue<int> pq;
    pq.push(3);
    pq.push(1);
    int n = pq.size();      // 2
    cout << "元素个数:" << n << endl;
    if (!pq.empty()) cout << "非空" << endl;
    return 0;
}

默认与自定义

priority_queue<int> pq; // 默认大顶堆

priority_queue<int, vector<int>, greater<int>> pq2; // 小顶堆

#include <queue>
#include <iostream>
#include <vector>
using namespace std;
int main() {
    priority_queue<int> pq;           // 默认大顶堆
    pq.push(3);
    pq.push(1);
    pq.push(2);
    cout << pq.top() << endl;   // 输出 3(最大的)

    priority_queue<int, vector<int>, greater<int>> pq2;  // 小顶堆
    pq2.push(3);
    pq2.push(1);
    pq2.push(2);
    cout << pq2.top() << endl;  // 输出 1(最小的)
    return 0;
}

场景:Top K 问题、任务调度、Dijkstra 算法、哈夫曼编码

2.9 <set> / <multiset> —— 有序集合C++

是什么

📚 set 是集合,元素不重复,自动从小到大排序。

📚 底层是红黑树。

📚 类比:自动排序且不允许重复的收纳盒。

📚 multiset 和 set 几乎一样,唯一区别是允许重复元素。

常用方法(每个方法附完整示例)

insert(x) —— 插入元素(自动排序,set 中重复会被忽略)

#include <set>
#include <iostream>
using namespace std;
int main() {
    set<int> s = {3, 1, 2};
    s.insert(4);     // {1,2,3,4}
    s.insert(2);     // 重复,无效,还是 {1,2,3,4}
    for (int x : s) cout << x << " ";
    cout << endl;
    return 0;
}

erase(x) —— 删除值为 x 的元素

#include <set>
#include <iostream>
using namespace std;
int main() {
    set<int> s = {3, 1, 2};
    s.erase(2);      // {1,3}
    for (int x : s) cout << x << " ";
    cout << endl;
    return 0;
}

erase(it) —— 删除迭代器指向的元素

#include <set>
#include <iostream>
using namespace std;
int main() {
    set<int> s = {3, 1, 2};
    s.erase(s.begin());  // 删除第一个,{2,3}
    for (int x : s) cout << x << " ";
    cout << endl;
    return 0;
}

find(x) —— 查找 x,返回迭代器,找不到返回 end()

#include <set>
#include <iostream>
using namespace std;
int main() {
    set<int> s = {3, 1, 2};
    auto it = s.find(3);
    if (it != s.end()) cout << "找到了" << endl;
    auto it2 = s.find(99);
    if (it2 == s.end()) cout << "没找到" << endl;
    return 0;
}

count(x) —— 统计 x 出现次数(set 为0或1,multiset 可更多)

#include <set>
#include <iostream>
using namespace std;
int main() {
    set<int> s = {3, 1, 2};
    int n = s.count(3);  // n = 1
    cout << "3出现次数:" << n << endl;
    return 0;
}

size() / empty() / clear()

#include <set>
#include <iostream>
using namespace std;
int main() {
    set<int> s = {3, 1, 2};
    int n = s.size();  // 3
    cout << "元素个数:" << n << endl;
    s.clear();         // 清空
    cout << "清空后元素个数:" << s.size() << endl;
    return 0;
}

lower_bound(x) —— 第一个 >= x 的迭代器

#include <set>
#include <iostream>
using namespace std;
int main() {
    set<int> s = {1, 3, 5};
    auto it = s.lower_bound(2);  // 指向第一个 >=2 的元素,即3
    cout << *it << endl;
    return 0;
}

upper_bound(x) —— 第一个 > x 的迭代器

#include <set>
#include <iostream>
using namespace std;
int main() {
    set<int> s = {1, 3, 5};
    auto it = s.upper_bound(3);  // 指向第一个 >3 的元素,即5
    cout << *it << endl;
    return 0;
}
#include <set>
#include <iostream>
using namespace std;
int main() {
    set<int> s = {3,1,2};
    for (int x : s) cout << x;   // 输出 123(自动排序)
    cout << endl;
    return 0;
}

特点

优点:自动排序,查找/插入/删除 O(log n)

缺点:不能 [] 随机访问,内存开销比 vector 大

场景:需要自动去重+排序、频繁查找

2.10 <map> / <multimap> —— 有序字典C++

是什么

📚 map 是键值对集合(key-value),按 key 自动排序,key 不重复。

📚 底层红黑树。

📚 类比:一本字典,key 是单词,value 是解释,按字母顺序排列。

📚 multimap 允许 key 重复。

常用方法(每个方法附完整示例)

insert({key, value}) —— 插入键值对

#include <map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    map<string, int> m;
    m.insert({"苹果", 5});
    m.insert({"香蕉", 3});
    cout << "苹果:" << m["苹果"] << endl;
    return 0;
}

erase(key) —— 删除指定 key

#include <map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    map<string, int> m;
    m["苹果"] = 5;
    m["香蕉"] = 3;
    m.erase("苹果");  // 删除苹果
    cout << "元素个数:" << m.size() << endl;
    return 0;
}

find(key) —— 查找 key,返回迭代器

#include <map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    map<string, int> m;
    m["苹果"] = 5;
    auto it = m.find("苹果");
    if (it != m.end()) cout << "苹果:" << it->second << endl;
    return 0;
}

count(key) —— 统计 key 出现次数(map 为0或1)

#include <map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    map<string, int> m;
    m["苹果"] = 5;
    if (m.count("苹果")) cout << "苹果存在" << endl;
    if (!m.count("香蕉")) cout << "香蕉不存在" << endl;
    return 0;
}

[key] —— 访问或插入(key 不存在会自动插入默认值!)

#include <map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    map<string, int> m;
    m["香蕉"] = 3;          // 插入或修改
    int x = m["香蕉"];      // x = 3
    cout << "香蕉:" << x << endl;
    // 注意:访问不存在的key会自动插入默认值0
    cout << "苹果:" << m["苹果"] << endl;  // 自动插入苹果:0
    return 0;
}

at(key) —— 访问(key 不存在抛异常,更安全)

#include <map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    map<string, int> m;
    m["香蕉"] = 3;
    int y = m.at("香蕉");   // y = 3
    cout << "香蕉:" << y << endl;
    // m.at("苹果") 会抛异常,因为苹果不存在
    return 0;
}

size() / empty() / clear()

#include <map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    map<string, int> m;
    m["苹果"] = 5;
    int n = m.size();       // 键值对个数
    cout << "元素个数:" << n << endl;
    m.clear();              // 清空
    cout << "清空后元素个数:" << m.size() << endl;
    return 0;
}

lower_bound / upper_bound

#include <map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    map<string, int> m;
    m["A"] = 1;
    m["B"] = 2;
    m["C"] = 3;
    auto it = m.lower_bound("B");  // 第一个 key >= "B"
    cout << it->first << ": " << it->second << endl;
    return 0;
}
#include <map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    map<string, int> scores;
    scores["Tom"] = 95;
    scores["Alice"] = 88;
    cout << scores["Tom"] << endl;     // 输出 95
    for (auto& p : scores)
        cout << p.first << ": " << p.second << endl;
    /* 输出(按 key 排序):
       Alice: 88
       Tom: 95  */
    return 0;
}
⚠️ [] 有副作用:key 不存在时会自动插入并设为默认值。

1. 只想判断是否存在,用 find() 或 count(),不要用 []。

2. 场景:需要 key-value 映射且 key 要排序、需要范围查询

2.11 <unordered_set> / <unordered_multiset> —— 无序集合(C++11)C++

是什么

📚 和 set 功能一样(存不重复元素),但底层是哈希表,元素不排序。

📚 类比:不排序的收纳盒,但找东西特别快。

和 set 的区别

unordered_set:平均 O(1) 查找,元素无序,内存稍大

set: O(log n) 查找,元素有序

常用方法(每个方法附完整示例)

unordered_set<int> us = {3, 1, 2};

和 set 基本一样的方法:

insert(x) —— 插入元素

#include <unordered_set>
#include <iostream>
using namespace std;
int main() {
    unordered_set<int> us = {3, 1, 2};
    us.insert(4);
    for (int x : us) cout << x << " ";
    cout << endl;
    return 0;
}

erase(x) —— 删除元素

#include <unordered_set>
#include <iostream>
using namespace std;
int main() {
    unordered_set<int> us = {3, 1, 2};
    us.erase(1);
    for (int x : us) cout << x << " ";
    cout << endl;
    return 0;
}

find(x) —— 查找,返回迭代器

#include <unordered_set>
#include <iostream>
using namespace std;
int main() {
    unordered_set<int> us = {3, 1, 2};
    if (us.find(2) != us.end()) cout << "有" << endl;
    if (us.find(99) == us.end()) cout << "无" << endl;
    return 0;
}

count(x) —— 统计出现次数

#include <unordered_set>
#include <iostream>
using namespace std;
int main() {
    unordered_set<int> us = {3, 1, 2};
    int n = us.count(3);  // 0或1
    cout << "3出现次数:" << n << endl;
    return 0;
}

size() / empty() / clear()

#include <unordered_set>
#include <iostream>
using namespace std;
int main() {
    unordered_set<int> us = {3, 1, 2};
    int n = us.size();
    cout << "元素个数:" << n << endl;
    us.clear();
    cout << "清空后元素个数:" << us.size() << endl;
    return 0;
}

哈希表特有方法:

bucket_count() —— 桶数量

#include <unordered_set>
#include <iostream>
using namespace std;
int main() {
    unordered_set<int> us = {3, 1, 2};
    int b = us.bucket_count();
    cout << "桶数量:" << b << endl;
    return 0;
}

load_factor() —— 负载因子(元素数/桶数)

#include <unordered_set>
#include <iostream>
using namespace std;
int main() {
    unordered_set<int> us = {3, 1, 2};
    float lf = us.load_factor();
    cout << "负载因子:" << lf << endl;
    return 0;
}

rehash(n) —— 重新设置桶数量为至少 n

#include <unordered_set>
#include <iostream>
using namespace std;
int main() {
    unordered_set<int> us;
    us.rehash(100);  // 提前扩容,避免插入时频繁 rehash
    cout << "桶数量:" << us.bucket_count() << endl;
    return 0;
}

场景:只需快速查找、不需要排序时,优先用 unordered_set

2.12 <unordered_map> / <unordered_multimap> —— 无序字典(C++11)C++

是什么

📚 和 map 功能一样(key-value),底层哈希表,key 不排序。

和 map 的区别

unordered_map:平均 O(1) 查找,key 无序

map: O(log n) 查找,key 有序

常用方法(每个方法附完整示例)

和 map 基本一样的方法:

insert({key, value}) —— 插入键值对

#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    unordered_map<string, int> um;
    um.insert({"a", 1});
    um.insert({"b", 2});
    cout << "a: " << um["a"] << endl;
    return 0;
}

erase(key) —— 删除指定 key

#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    unordered_map<string, int> um;
    um["a"] = 1;
    um["b"] = 2;
    um.erase("a");
    cout << "元素个数:" << um.size() << endl;
    return 0;
}

find(key) —— 查找 key

#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    unordered_map<string, int> um;
    um["a"] = 1;
    if (um.find("a") != um.end()) cout << "有" << endl;
    if (um.find("z") == um.end()) cout << "无" << endl;
    return 0;
}

count(key) —— 统计 key 出现次数

#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    unordered_map<string, int> um;
    um["a"] = 1;
    int n = um.count("a");  // 0或1
    cout << "a出现次数:" << n << endl;
    return 0;
}

[key] —— 访问或插入

#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    unordered_map<string, int> um;
    um["b"] = 2;
    int x = um["b"];
    cout << "b: " << x << endl;
    return 0;
}

at(key) —— 安全访问(不存在抛异常)

#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    unordered_map<string, int> um;
    um["b"] = 2;
    int y = um.at("b");
    cout << "b: " << y << endl;
    return 0;
}

size() / empty() / clear()

#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;
int main() {
    unordered_map<string, int> um;
    um["a"] = 1;
    int n = um.size();
    cout << "元素个数:" << n << endl;
    um.clear();
    cout << "清空后元素个数:" << um.size() << endl;
    return 0;
}

场景:需要 key-value 映射但不需要排序时,优先用 unordered_map(更快)

容器选择速查表

需求 选择

动态数组、随机访问 vector

频繁中间增删 list

头尾都操作 deque

先进先出 queue

后进先出 stack

自动排序+去重 set

自动排序+键值对 map

快速查找不需排序 unordered_set/map

第三章 算法

算法是什么

<algorithm> 提供一大堆现成函数,操作容器里的数据。

不需要自己写排序、查找、复制,直接调用。

类比:工具箱里的各种工具,需要什么拿什么。

大部分算法用"迭代器"指定操作范围 [first, last)——左闭右开。

例如 sort(v.begin(), v.end()) 对整个 vector 排序。

3.1 <algorithm> —— 通用算法C++

查找类

find(first, last, x)

找第一个等于 x 的元素,返回迭代器,找不到返回 last。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 3, 5, 7, 9};
    auto it = find(v.begin(), v.end(), 5);
    if (it != v.end()) cout << "找到了:" << *it << endl;
    else cout << "没找到" << endl;
    return 0;
}

find_if(first, last, 条件函数)

找第一个满足条件的元素。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 3, 4, 7, 9};
    // 找第一个偶数
    auto it = find_if(v.begin(), v.end(),
        [](int x){ return x % 2 == 0; });
    if (it != v.end()) cout << "第一个偶数:" << *it << endl;
    return 0;
}

count(first, last, x)

统计 x 出现次数。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 3, 3, 7, 3};
    int n = count(v.begin(), v.end(), 3);
    cout << "3出现次数:" << n << endl;  // 3
    return 0;
}

count_if(first, last, 条件)

按条件统计。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 2, 3, 4, 5, 6};
    // 统计偶数个数
    int n = count_if(v.begin(), v.end(),
        [](int x){ return x%2==0; });
    cout << "偶数个数:" << n << endl;  // 3
    return 0;
}

binary_search(first, last, x)

要求序列已排序!判断 x 是否存在,返回 bool。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 3, 5, 7, 9};  // 已排序
    bool exists = binary_search(v.begin(), v.end(), 5);
    cout << "5是否存在:" << (exists ? "是" : "否") << endl;
    return 0;
}

lower_bound / upper_bound(要求已排序)

lower_bound:第一个 >= x 的位置

upper_bound:第一个 > x 的位置

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 3, 5, 5, 7};  // 已排序
    auto it1 = lower_bound(v.begin(), v.end(), 5);  // 第一个 >=5
    auto it2 = upper_bound(v.begin(), v.end(), 5);  // 第一个 >5
    cout << "lower_bound指向:" << *it1 << endl;
    cout << "5的个数:" << it2 - it1 << endl;  // 2
    return 0;
}

排序类

sort(first, last)

默认升序排序。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {3, 1, 4, 1, 5};
    sort(v.begin(), v.end());
    for (int x : v) cout << x << " ";  // 1 1 3 4 5
    cout << endl;
    return 0;
}

sort(first, last, 比较函数)

自定义排序。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {3, 1, 4, 1, 5};
    // 降序排序
    sort(v.begin(), v.end(), greater<int>());
    for (int x : v) cout << x << " ";  // 5 4 3 1 1
    cout << endl;
    // 自定义:按绝对值排序
    vector<int> v2 = {-3, 1, -4, 2};
    sort(v2.begin(), v2.end(), [](int a,int b){ return abs(a)<abs(b); });
    for (int x : v2) cout << x << " ";  // 1 2 -3 -4
    cout << endl;
    return 0;
}

stable_sort

稳定排序,相等元素的相对顺序保持不变。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {3, 1, 4, 1, 5};
    stable_sort(v.begin(), v.end());
    for (int x : v) cout << x << " ";
    cout << endl;
    return 0;
}

partial_sort

只把前 N 个排好序,后面不管,比全排序快。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {5, 3, 1, 4, 2};
    partial_sort(v.begin(), v.begin()+3, v.end());  // 只排前3个
    for (int x : v) cout << x << " ";  // 1 2 3 5 4(前3个有序)
    cout << endl;
    return 0;
}

nth_element

第 N 个位置放正确元素(左边都小,右边都大),左右不一定有序。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {5, 3, 1, 4, 2};
    nth_element(v.begin(), v.begin()+2, v.end());
    cout << "第3小的元素:" << v[2] << endl;  // 3
    return 0;
}

reverse(first, last)

反转。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 2, 3};
    reverse(v.begin(), v.end());  // {1,2,3} → {3,2,1}
    for (int x : v) cout << x << " ";
    cout << endl;
    return 0;
}

is_sorted(first, last)

判断是否已排序。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    if (is_sorted(v.begin(), v.end())) cout << "已排序" << endl;
    else cout << "未排序" << endl;
    return 0;
}

修改类

copy(first, last, dest)

复制到从 dest 开始的位置。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> src={1,2,3}, dst(3);
    copy(src.begin(), src.end(), dst.begin());
    for (int x : dst) cout << x << " ";  // 1 2 3
    cout << endl;
    return 0;
}

fill(first, last, x)

范围内所有元素设为 x。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    fill(v.begin(), v.end(), 0);  // 全部填0
    for (int x : v) cout << x << " ";  // 0 0 0 0 0
    cout << endl;
    return 0;
}

replace(first, last, old, new)

所有等于 old 的元素换成 new。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 2, 1, 3, 1};
    replace(v.begin(), v.end(), 1, 99);  // 所有1变成99
    for (int x : v) cout << x << " ";  // 99 2 99 3 99
    cout << endl;
    return 0;
}

transform(first, last, dest, 函数)

对每个元素执行操作,结果存到 dest。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 2, 3};
    // 每个元素乘2,结果存回v
    transform(v.begin(), v.end(), v.begin(),
        [](int x){ return x*2; });
    for (int x : v) cout << x << " ";  // 2 4 6
    cout << endl;
    return 0;
}

remove / remove_if

⚠️ remove 不会真正删除,只是把要保留的移到前面,返回新末尾迭代器。

1. 要真正删除需配合 erase(删除-擦除惯用法): v.erase(remove(v.begin(), v.end(), 5), v.end()); [示例] #include <algorithm> #include <vector> #include <iostream> using namespace std; int main() { vector<int> v = {1, 2, 3, 4, 5, 6}; // remove_if 删除所有偶数 v.erase(remove_if(v.begin(), v.end(), [](int x){ return x%2==0; }), v.end()); for (int x : v) cout << x << " "; // 1 3 5 cout << endl; return 0; } unique 同样不会真正删除,把重复元素移到后面。

2. 通常先排序再去重: sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); [示例] #include <algorithm> #include <vector> #include <iostream> using namespace std; int main() { vector<int> v={1,1,2,2,3}; sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); // {1,2,3} for (int x : v) cout << x << " "; cout << endl; return 0; } swap(a, b) 交换两个变量或容器。

3. [示例] #include <algorithm> #include <vector> #include <iostream> using namespace std; int main() { int a=1, b=2; swap(a, b); // a=2, b=1 cout << "a=" << a << ", b=" << b << endl; vector<int> v1={1,2}, v2={3,4}; swap(v1, v2); // 交换两个vector return 0; }

最值类

min(a, b) / max(a, b) 两个数的最小/最大

#include <algorithm>
#include <iostream>
using namespace std;
int main() {
    int m = min(3, 5);  // m = 3
    int M = max(3, 5);  // M = 5
    cout << "min=" << m << ", max=" << M << endl;
    return 0;
}

min_element / max_element 范围内最小/最大元素(返回迭代器)

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {3, 1, 4, 1, 5};
    auto it = min_element(v.begin(), v.end());
    cout << "最小值:" << *it << endl;  // 1
    auto it2 = max_element(v.begin(), v.end());
    cout << "最大值:" << *it2 << endl; // 5
    return 0;
}

minmax_element 同时找最小和最大(返回 pair)

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {3, 1, 4, 1, 5};
    auto p = minmax_element(v.begin(), v.end());
    cout << "最小:" << *p.first << ",最大:" << *p.second << endl;
    return 0;
}

其他常用

for_each(first, last, 函数)

对每个元素执行操作。范围 for 更直观,这个用得少了。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 2, 3};
    for_each(v.begin(), v.end(), [](int x){ cout << x << " "; });
    cout << endl;
    return 0;
}

merge

合并两个有序序列为一个有序序列。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> a={1,3}, b={2,4}, c(4);
    merge(a.begin(),a.end(), b.begin(),b.end(), c.begin());
    // c = {1,2,3,4}
    for (int x : c) cout << x << " ";
    cout << endl;
    return 0;
}

next_permutation

生成字典序下一个排列,常用于全排列枚举。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1,2,3};
    do {
        for (int x : v) cout << x << " ";
        cout << endl;
    } while (next_permutation(v.begin(), v.end()));
    return 0;
}

shuffle / random_shuffle

随机打乱。

#include <algorithm>
#include <vector>
#include <iostream>
#include <random>
#include <ctime>
using namespace std;
int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    shuffle(v.begin(), v.end(), mt19937(time(0)));
    for (int x : v) cout << x << " ";
    cout << endl;
    return 0;
}

集合操作(要求已排序)

set_union 并集 | set_intersection 交集 | set_difference 差集 | includes 包含

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> a={1,2,3}, b={2,3,4}, c(10);
    // 并集
    auto it = set_union(a.begin(),a.end(), b.begin(),b.end(), c.begin());
    for (auto p = c.begin(); p != it; ++p) cout << *p << " ";
    cout << endl;  // 1 2 3 4
    // 判断 b 是否包含于 a
    bool ok = includes(a.begin(),a.end(), b.begin(),b.end());
    cout << "b包含于a:" << (ok ? "是" : "否") << endl;  // 否
    return 0;
}

3.2 <numeric> —— 数值算法C++

accumulate(first, last, 初始值)

累加求和。

#include <numeric>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    int sum = accumulate(v.begin(), v.end(), 0);
    cout << "和:" << sum << endl;  // 15
    // 也可自定义操作(如累乘)
    int prod = accumulate(v.begin(), v.end(), 1, multiplies<int>());
    cout << "积:" << prod << endl;  // 120
    return 0;
}

partial_sum(first, last, dest)

前缀和。

#include <numeric>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1,2,3,4}, result(4);
    partial_sum(v.begin(), v.end(), result.begin());
    // result = {1, 3, 6, 10}
    for (int x : result) cout << x << " ";
    cout << endl;
    return 0;
}

adjacent_difference 相邻差

#include <numeric>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1,3,6,10}, result(4);
    adjacent_difference(v.begin(), v.end(), result.begin());
    // result = {1, 2, 3, 4}
    for (int x : result) cout << x << " ";
    cout << endl;
    return 0;
}

inner_product 内积(对应位置相乘再相加)

#include <numeric>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> a = {1,2,3}, b = {4,5,6};
    int dot = inner_product(a.begin(), a.end(), b.begin(), 0);
    // dot = 1*4 + 2*5 + 3*6 = 32
    cout << "内积:" << dot << endl;
    return 0;
}

iota(first, last, 起始值)(C++11)

从起始值开始递增填充。

#include <numeric>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v(5);
    iota(v.begin(), v.end(), 1);  // v = {1,2,3,4,5}
    for (int x : v) cout << x << " ";
    cout << endl;
    return 0;
}

gcd / lcm(C++17)

最大公约数 / 最小公倍数。

#include <numeric>
#include <iostream>
using namespace std;
int main() {
    cout << "gcd(12,18)=" << gcd(12,18) << endl;  // 6
    cout << "lcm(12,18)=" << lcm(12,18) << endl;  // 36
    return 0;
}
第四章 字符串与字符处理

4.1 <string> —— 字符串(最常用!)C++

是什么

📚 C++ 字符串类,比 C 字符数组好用太多。

📚 自动管理内存,支持拼接、比较、查找。

📚 类比:专门装文字的"智能盒子"。

创建方式

string s1; // 空字符串

string s2 = "Hello"; // 用C字符串初始化

string s3(5, 'a'); // "aaaaa"

string s4 = s2 + " World"; // 拼接

常用方法一览(每个方法附完整示例)

【长度相关】

size() / length() —— 字符个数(两者一样)

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    int n = s.size();   // n = 11
    cout << "长度:" << n << endl;
    return 0;
}

empty() —— 是否为空

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s;
    if (s.empty()) cout << "空" << endl;
    s = "hello";
    if (!s.empty()) cout << "非空" << endl;
    return 0;
}

capacity() —— 当前容量

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello";
    int c = s.capacity();
    cout << "容量:" << c << endl;
    return 0;
}

reserve(n) —— 预留容量

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s;
    s.reserve(100);  // 提前分配,避免频繁扩容
    cout << "容量:" << s.capacity() << endl;
    return 0;
}

shrink_to_fit() —— 释放多余容量

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello";
    s.reserve(100);
    cout << "释放前容量:" << s.capacity() << endl;
    s.shrink_to_fit();
    cout << "释放后容量:" << s.capacity() << endl;
    return 0;
}

【访问字符】

s[i] —— 第 i 个字符(越界不报错)

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    char c = s[0];   // c = 'H'
    cout << "第一个字符:" << c << endl;
    return 0;
}

s.at(i) —— 同上,越界抛异常(更安全)

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    char c = s.at(1); // c = 'e'
    cout << "第二个字符:" << c << endl;
    return 0;
}

s.front() / s.back() —— 首/尾字符

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    char f = s.front(); // 'H'
    char b = s.back();  // 'd'
    cout << "首:" << f << ",尾:" << b << endl;
    return 0;
}

s.c_str() / s.data() —— 转 C 风格 const char*

#include <string>
#include <cstdio>
using namespace std;
int main() {
    string s = "Hello World";
    const char* p = s.c_str();
    printf("%s\n", p);
    return 0;
}

【修改字符串】

s += "abc" / s.append("abc") —— 追加

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    s += "!";          // "Hello World!"
    s.append("!!!");   // 追加
    cout << s << endl;
    return 0;
}

s.push_back('a') —— 末尾加一个字符

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello";
    s.push_back('!');
    cout << s << endl;  // Hello!
    return 0;
}

s.pop_back() —— 删除末尾字符

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello!";
    s.pop_back();     // 删掉最后一个字符
    cout << s << endl;  // Hello
    return 0;
}

s.insert(pos, str) —— pos 位置插入

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    s.insert(5, ","); // "Hello, World"
    cout << s << endl;
    return 0;
}

s.erase(pos, len) —— 从 pos 删 len 个字符

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    s.erase(5, 6);    // 从第5个删6个 → "Hello"
    cout << s << endl;
    return 0;
}

s.replace(pos, len, str) —— 替换

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    s.replace(6, 5, "C++");  // "Hello C++"
    cout << s << endl;
    return 0;
}

s.clear() —— 清空

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello";
    s.clear();        // 变成空字符串
    cout << "长度:" << s.size() << endl;
    return 0;
}

s.swap(s2) —— 交换两个字符串

#include <string>
#include <iostream>
using namespace std;
int main() {
    string a="1", b="2";
    a.swap(b);  // a="2", b="1"
    cout << "a=" << a << ", b=" << b << endl;
    return 0;
}

【查找】

s.find(str) —— 第一次出现位置,找不到返回 string::npos

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    int pos = s.find("World");  // pos = 6
    cout << "位置:" << pos << endl;
    if (s.find("xyz") == string::npos) cout << "没找到" << endl;
    return 0;
}

s.rfind(str) —— 从后往前找

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    int pos = s.rfind("o");    // 最后一个o的位置 = 7
    cout << "位置:" << pos << endl;
    return 0;
}

s.find_first_of(chars) —— chars 中任意字符首次出现位置

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    int pos = s.find_first_of("aeiou");  // 第一个元音位置 = 1
    cout << "位置:" << pos << endl;
    return 0;
}

s.find_last_of(chars) —— chars 中任意字符末次出现位置

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    int pos = s.find_last_of("aeiou");  // 最后一个元音位置 = 7
    cout << "位置:" << pos << endl;
    return 0;
}

【比较】

s1 == s2 / != / < / > —— 按字典序比较

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello";
    if (s == "Hello") cout << "相等" << endl;
    if (s < "World") cout << "Hello < World" << endl;
    return 0;
}

s1.compare(s2) —— 相等返回0,小于返回负数

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello";
    int r = s.compare("Hello");  // r = 0
    cout << "比较结果:" << r << endl;
    return 0;
}

【子串】

s.substr(pos, len) —— 从 pos 取 len 个字符

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello World";
    string sub = s.substr(0, 5);  // "Hello"
    cout << sub << endl;
    return 0;
}

【数值转换(C++11)】

stoi(str) / stol / stoll —— 字符串转 int/long/long long

#include <string>
#include <iostream>
using namespace std;
int main() {
    int n = stoi("123");   // n = 123
    cout << "n=" << n << endl;
    return 0;
}

stod(str) —— 字符串转 double

#include <string>
#include <iostream>
using namespace std;
int main() {
    double d = stod("3.14");  // d = 3.14
    cout << "d=" << d << endl;
    return 0;
}

to_string(x) —— 数值转字符串

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = to_string(456);  // s = "456"
    cout << "s=" << s << endl;
    return 0;
}

遍历:for (char c : s) cout << c;

#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = "Hello";
    for (char c : s) cout << c << " ";
    cout << endl;
    return 0;
}
⚠️ 1. - 下标从 0 开始 - 中文 UTF-8 编码下一个字占3字节,size() 返回字节数不是字数 - 大量拼接用 += 或 append,不要用 s = s + "..."(会创建临时对象)

4.2 <string_view> —— 字符串视图(C++17)C++

是什么

📚 字符串的"只读视图",不拥有数据,只是"借用"别人的字符串。

📚 类比:给你一张写着文字的纸的"照片",能看不能改,也不用复印。

为什么需要

函数参数用 string 会拷贝一份,浪费时间内存。

用 string_view 不拷贝,直接"看"原字符串。

#include <string_view>
#include <iostream>
#include <string>
using namespace std;
void print(string_view sv) { cout << sv << endl; }
int main() {
    string s = "Hello";
    print(s);         // 可传 string
    print("World");   // 可传 C 字符串
    return 0;
}

常用方法:和 string 的只读方法一样(size、[]、at、substr、find、data)

没有 push_back、append、+= 等修改方法。

size() —— 字符个数

#include <string_view>
#include <iostream>
using namespace std;
int main() {
    string_view sv = "Hello";
    int n = sv.size();  // n = 5
    cout << "长度:" << n << endl;
    return 0;
}

[] / at() —— 访问字符

#include <string_view>
#include <iostream>
using namespace std;
int main() {
    string_view sv = "Hello";
    char c = sv[0];   // 'H'
    cout << "第一个字符:" << c << endl;
    return 0;
}

substr(pos, len) —— 子串(返回新的 string_view,不拷贝)

#include <string_view>
#include <iostream>
using namespace std;
int main() {
    string_view sv = "Hello";
    string_view sub = sv.substr(0, 3);  // "Hel"
    cout << sub << endl;
    return 0;
}

find(str) —— 查找

#include <string_view>
#include <iostream>
using namespace std;
int main() {
    string_view sv = "Hello";
    int pos = sv.find("ll");  // pos = 2
    cout << "位置:" << pos << endl;
    return 0;
}

data() —— 底层指针

#include <string_view>
#include <cstdio>
using namespace std;
int main() {
    string_view sv = "Hello";
    const char* p = sv.data();
    printf("%s\n", p);
    return 0;
}
⚠️ string_view 不拥有数据,原字符串销毁后它就失效(悬空)。

1. 不要长期存储 string_view,只用作函数参数。

4.3 <cctype> —— 字符判断与转换C 兼容

是什么

一组函数,判断单个字符是什么类型,或转换大小写。

常用函数(每个函数附完整示例)

isalpha(c) —— 是否字母(a-z, A-Z)

#include <cctype>
#include <iostream>
using namespace std;
int main() {
    char c = 'A';
    if (isalpha((unsigned char)c)) cout << "是字母" << endl;
    return 0;
}

isdigit(c) —— 是否数字(0-9)

#include <cctype>
#include <iostream>
using namespace std;
int main() {
    if (isdigit('5')) cout << "是数字" << endl;
    return 0;
}

isalnum(c) —— 是否字母或数字

#include <cctype>
#include <iostream>
using namespace std;
int main() {
    if (isalnum('a')) cout << "字母或数字" << endl;
    return 0;
}

isspace(c) —— 是否空白(空格/Tab/换行)

#include <cctype>
#include <iostream>
using namespace std;
int main() {
    if (isspace(' ')) cout << "是空白" << endl;
    return 0;
}

isupper(c) —— 是否大写字母

#include <cctype>
#include <iostream>
using namespace std;
int main() {
    if (isupper('A')) cout << "大写" << endl;
    return 0;
}

islower(c) —— 是否小写字母

#include <cctype>
#include <iostream>
using namespace std;
int main() {
    if (islower('a')) cout << "小写" << endl;
    return 0;
}

ispunct(c) —— 是否标点

#include <cctype>
#include <iostream>
using namespace std;
int main() {
    if (ispunct(',')) cout << "是标点" << endl;
    return 0;
}

isprint(c) —— 是否可打印

#include <cctype>
#include <iostream>
using namespace std;
int main() {
    if (isprint('A')) cout << "可打印" << endl;
    return 0;
}

toupper(c) —— 转大写

#include <cctype>
#include <iostream>
using namespace std;
int main() {
    char d = toupper('a');  // d = 'A'
    cout << d << endl;
    return 0;
}

tolower(c) —— 转小写

#include <cctype>
#include <iostream>
using namespace std;
int main() {
    char d = tolower('A');  // d = 'a'
    cout << d << endl;
    return 0;
}
#include <cctype>
#include <iostream>
using namespace std;
int main() {
    char c = 'A';
    if (isupper(c)) cout << "是大写字母" << endl;
    char d = tolower(c);  // d = 'a'
    cout << "转换后:" << d << endl;
    return 0;
}

isblank(字符) —— 是否为空白字符(空格或制表符,C99)

#include <cctype>
#include <iostream>
using namespace std;
int main() {
    cout << isblank(' ') << endl;   // 非0(是空白)
    cout << isblank('\t') << endl;  // 非0(是空白)
    cout << isblank('a') << endl;   // 0(不是)
    return 0;
}

iscntrl(字符) —— 是否为控制字符(如\n、\t、\r等)

isgraph(字符) —— 是否为可打印非空白字符(有可见图形)

isxdigit(字符) —— 是否为十六进制数字(0-9, a-f, A-F)

#include <cctype>
#include <iostream>
using namespace std;
int main() {
    cout << isxdigit('A') << endl;  // 非0(是十六进制)
    cout << isxdigit('g') << endl;  // 0(不是)
    cout << isgraph('!') << endl;   // 非0(可打印非空白)
    return 0;
}
⚠️ 参数是 int,char 为负数时可能出问题,建议转 unsigned char:

1. isalpha((unsigned char)c)

4.4 <cstring> —— C 风格字符串操作C 兼容

是什么

📚 C 语言字符串函数,操作以 '\0' 结尾的字符数组。

📚 C++ 推荐用 string,但和 C 代码交互时还会遇到。

常用函数(每个函数附完整示例)

strlen(s) —— 字符串长度(不含 '\0')

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    char src[50] = "Hello";
    int n = strlen(src);  // n = 5
    cout << "长度:" << n << endl;
    return 0;
}

strcpy(dest, src) —— 复制(不安全,可能越界!)

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    char src[50] = "Hello", dest[50];
    strcpy(dest, src);  // dest = "Hello"
    cout << dest << endl;
    return 0;
}

strncpy(dest, src, n) —— 最多复制 n 个(相对安全)

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    char src[50] = "Hello", dest[50] = {0};
    strncpy(dest, src, 3);  // dest = "Hel"
    cout << dest << endl;
    return 0;
}

strcat(dest, src) —— 拼接

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    char dest[50] = "Hello";
    strcat(dest, " World");  // dest = "Hello World"
    cout << dest << endl;
    return 0;
}

strncat(dest, src, n) —— 最多拼 n 个

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    char dest[50] = "Hello";
    strncat(dest, " ABC", 2);  // 拼 " A"
    cout << dest << endl;
    return 0;
}

strcmp(s1, s2) —— 比较,相等返回0

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    if (strcmp("abc", "abc") == 0) cout << "相等" << endl;
    return 0;
}

strncmp(s1, s2, n) —— 比较前 n 个

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    int r = strncmp("abc", "abd", 2);  // 前2个相等,返回0
    cout << "比较结果:" << r << endl;
    return 0;
}

strchr(s, c) —— 字符 c 首次出现位置

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    char* p = strchr("Hello", 'l');  // 指向第一个'l'
    cout << p << endl;  // llo
    return 0;
}

strrchr(s, c) —— 字符 c 末次出现位置

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    char* p = strrchr("Hello", 'l');  // 指向最后一个'l'
    cout << p << endl;  // lo
    return 0;
}

strstr(s1, s2) —— 子串 s2 在 s1 中位置

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    char* p = strstr("Hello World", "World");  // 指向"World"
    cout << p << endl;
    return 0;
}

内存操作

memset(ptr, val, n) —— n 字节设为 val

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    int arr[5];
    memset(arr, 0, sizeof(arr));  // 全部清零
    cout << arr[0] << endl;
    return 0;
}

memcpy(dest, src, n) —— 复制 n 字节(不允许重叠)

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    int a[5]={1,2,3,4,5}, b[5];
    memcpy(b, a, sizeof(a));
    cout << b[0] << endl;
    return 0;
}

memmove(dest, src, n) —— 复制 n 字节(允许重叠,更安全)

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    int arr[5] = {1,2,3,4,5};
    memmove(arr+1, arr, 4*sizeof(int));  // 向后移动
    for (int i=0;i<5;i++) cout << arr[i] << " ";
    cout << endl;
    return 0;
}

memcmp(p1, p2, n) —— 比较前 n 字节

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    int a[5]={1,2,3,4,5}, b[5]={1,2,3,4,5};
    if (memcmp(a, b, sizeof(a)) == 0) cout << "相同" << endl;
    return 0;
}

strerror(错误码) —— 把错误码转成人类可读的字符串(常配合 errno 使用)

#include <cstring>
#include <cerrno>
#include <cstdio>
#include <iostream>
using namespace std;
int main() {
    FILE* fp = fopen("不存在的文件.txt", "r");
    if (fp == NULL) {
        cout << "错误:" << strerror(errno) << endl;
    }
    return 0;
}

strtok(字符串, 分隔符) —— 字符串分割(注意:会修改原字符串,且不可重入)

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    char str[] = "apple,banana,orange";
    char* token = strtok(str, ",");
    while (token != NULL) {
        cout << token << endl;
        token = strtok(NULL, ",");
    }
    return 0;
}

memchr(指针, 字符, 字节数) —— 在内存中查找字符首次出现位置

#include <cstring>
#include <iostream>
using namespace std;
int main() {
    char str[] = "Hello World";
    char* p = (char*)memchr(str, 'W', strlen(str));
    if (p) cout << "找到:" << p << endl;
    return 0;
}

strspn(字符串1, 字符串2) —— 字符串1开头连续包含字符串2中字符的个数

strcspn(字符串1, 字符串2) —— 字符串1开头连续不包含字符串2中字符的个数

strpbrk(字符串1, 字符串2) —— 查找字符串2中任一字符在字符串1中首次出现的位置

⚠️ strcpy、strcat 不检查缓冲区大小,易造成缓冲区溢出。

1. C++ 中尽量用 string,不要用这些函数。

第五章 数学与数值

5.1 <cmath> —— 数学函数C 兼容

常用函数一览(每个函数附完整示例)

【基本】

abs(x) / fabs(x) —— 绝对值(fabs 专门用于浮点)

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    int a = abs(-5);      // a = 5
    double b = fabs(-3.14); // b = 3.14
    cout << "a=" << a << ", b=" << b << endl;
    return 0;
}

fmod(x, y) —— 浮点数取余

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double r = fmod(5.5, 2.0);  // r = 1.5
    cout << "r=" << r << endl;
    return 0;
}

【幂与指数】

pow(x, y) —— x 的 y 次方

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double r = pow(2, 10);  // r = 1024
    cout << "r=" << r << endl;
    return 0;
}

sqrt(x) —— 平方根

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double r = sqrt(2);    // r ≈ 1.414
    cout << "r=" << r << endl;
    return 0;
}

cbrt(x) —— 立方根(C99)

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double r = cbrt(27);   // r = 3
    cout << "r=" << r << endl;
    return 0;
}

exp(x) —— e 的 x 次方

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double r = exp(1);     // r ≈ 2.718
    cout << "r=" << r << endl;
    return 0;
}

exp2(x) —— 2 的 x 次方(C99)

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double r = exp2(10);   // r = 1024
    cout << "r=" << r << endl;
    return 0;
}

log(x) —— 自然对数(ln)

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double r = log(2.718); // r ≈ 1
    cout << "r=" << r << endl;
    return 0;
}

log2(x) —— 以2为底(C99)

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double r = log2(1024); // r = 10
    cout << "r=" << r << endl;
    return 0;
}

log10(x) —— 以10为底

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double r = log10(100); // r = 2
    cout << "r=" << r << endl;
    return 0;
}

【三角函数】(参数是弧度,不是角度!)

sin / cos / tan

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double s = sin(3.14159/2);  // ≈ 1
    double c = cos(0);          // = 1
    double t = tan(0);          // = 0
    cout << "sin=" << s << ", cos=" << c << ", tan=" << t << endl;
    return 0;
}

asin / acos / atan —— 反三角

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double a = asin(1);    // ≈ π/2
    double b = acos(0);    // ≈ π/2
    cout << "asin=" << a << ", acos=" << b << endl;
    return 0;
}

atan2(y, x) —— 反正切(能判断象限)

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double a = atan2(1, 1);  // ≈ π/4
    cout << "atan2=" << a << endl;
    return 0;
}

角度转弧度:弧度 = 角度 * π / 180

【双曲函数】

sinh / cosh / tanh

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double s = sinh(0);    // = 0
    double c = cosh(0);    // = 1
    cout << "sinh=" << s << ", cosh=" << c << endl;
    return 0;
}

asinh / acosh / atanh(C99)

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double a = asinh(0);   // = 0
    cout << "asinh=" << a << endl;
    return 0;
}

【取整】

floor(x) —— 向下取整

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    cout << "floor(3.7)=" << floor(3.7) << endl;    // 3
    cout << "floor(-3.7)=" << floor(-3.7) << endl;  // -4
    return 0;
}

ceil(x) —— 向上取整

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    cout << "ceil(3.2)=" << ceil(3.2) << endl;    // 4
    cout << "ceil(-3.2)=" << ceil(-3.2) << endl;  // -3
    return 0;
}

round(x) —— 四舍五入

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    cout << "round(3.5)=" << round(3.5) << endl;    // 4
    cout << "round(-3.5)=" << round(-3.5) << endl;  // -4
    return 0;
}

trunc(x) —— 向零取整

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    cout << "trunc(3.7)=" << trunc(3.7) << endl;    // 3
    cout << "trunc(-3.7)=" << trunc(-3.7) << endl;  // -3
    return 0;
}

【其他】

min(x,y) / max(x,y) —— 两数最小/最大(注意:在 <algorithm> 中,不在 <cmath>)

📌 C++ 中 std::min/std::max 定义在 <algorithm> 头文件中,C 语言没有这两个函数

#include <algorithm>
#include <iostream>
using namespace std;
int main() {
    int m = min(3, 5);  // 3
    int M = max(3, 5);  // 5
    cout << "min=" << m << ", max=" << M << endl;
    return 0;
}

hypot(x, y) —— sqrt(x²+y²),斜边

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    double h = hypot(3, 4);  // h = 5
    cout << "hypot=" << h << endl;
    return 0;
}

isnan(x) —— 是否非数(NaN)

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    if (isnan(0.0/0.0)) cout << "不是数" << endl;
    return 0;
}

isinf(x) —— 是否无穷大

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    if (isinf(1.0/0.0)) cout << "无穷大" << endl;
    return 0;
}

isfinite(x) —— 是否有限值

#include <cmath>
#include <iostream>
using namespace std;
int main() {
    if (isfinite(3.14)) cout << "有限值" << endl;
    return 0;
}
#include <cmath>
#include <iostream>
using namespace std;
int main() {
    cout << sin(3.14159) << endl;       // 正弦
    cout << sqrt(2) << endl;            // 根号2 ≈ 1.414
    cout << pow(2, 10) << endl;         // 1024
    cout << floor(3.9) << endl;         // 3
    return 0;
}
⚠️ 三角函数用弧度不是角度。

1. M_PI(圆周率)非标准,部分编译器需 #define _USE_MATH_DEFINES。

2. C++20 可用 <numbers> 中的 std::numbers::pi。

5.2 <cstdlib> —— 随机数与通用工具C 兼容

常用函数(每个函数附完整示例)

rand() —— 生成 0 到 RAND_MAX 的随机整数

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    int r = rand();
    cout << "随机数:" << r << endl;
    return 0;
}

srand(seed) —— 设置随机数种子(不设则每次序列相同)

#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;
int main() {
    srand(time(0));  // 用时间播种,需 <ctime>
    cout << rand() << endl;
    return 0;
}

生成指定范围

#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;
int main() {
    srand(time(0));
    int r1 = rand() % 100;          // 0~99
    int r2 = rand() % 100 + 1;      // 1~100
    double r3 = (double)rand() / RAND_MAX;  // 0.0~1.0
    cout << "r1=" << r1 << ", r2=" << r2 << ", r3=" << r3 << endl;
    return 0;
}

abs / labs / llabs —— 整数绝对值

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    int a = abs(-5);        // 5
    long b = labs(-100L);   // 100
    cout << "a=" << a << ", b=" << b << endl;
    return 0;
}

div(x, y) —— 整数除法,返回商和余数

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    div_t r = div(10, 3);   // r.quot=3, r.rem=1
    cout << "商=" << r.quot << ", 余数=" << r.rem << endl;
    return 0;
}

exit(0) —— 立即退出程序

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    cout << "准备退出" << endl;
    exit(0);  // 正常退出
    cout << "不会执行到这里" << endl;
    return 0;
}

abort() —— 异常终止

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    // abort();  // 异常终止,不做清理(取消注释可测试)
    cout << "abort会异常终止程序" << endl;
    return 0;
}

system("命令") —— 执行系统命令

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    // system("pause");  // Windows下暂停,等待按键
    cout << "system可执行系统命令" << endl;
    return 0;
}

malloc(字节数) —— 动态分配内存(返回 void*,失败返回 NULL)

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    int* arr = (int*)malloc(5 * sizeof(int));  // 分配5个int的空间
    if (arr == NULL) {
        cout << "内存分配失败" << endl;
        return 1;
    }
    for (int i = 0; i < 5; i++) {
        arr[i] = i * 10;
        cout << arr[i] << " ";
    }
    cout << endl;
    free(arr);  // 释放内存
    return 0;
}

calloc(个数, 大小) —— 分配内存并初始化为0

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    int* arr = (int*)calloc(5, sizeof(int));  // 分配5个int,全部初始化为0
    if (arr) {
        for (int i = 0; i < 5; i++) {
            cout << arr[i] << " ";  // 输出 0 0 0 0 0
        }
        cout << endl;
        free(arr);
    }
    return 0;
}

realloc(指针, 新大小) —— 重新分配内存(可扩大或缩小)

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    int* arr = (int*)malloc(3 * sizeof(int));
    arr[0] = 1; arr[1] = 2; arr[2] = 3;
    // 扩大到5个int
    int* new_arr = (int*)realloc(arr, 5 * sizeof(int));
    if (new_arr) {
        arr = new_arr;
        arr[3] = 4; arr[4] = 5;
        for (int i = 0; i < 5; i++) cout << arr[i] << " ";
        cout << endl;
    }
    free(arr);
    return 0;
}

free(指针) —— 释放动态分配的内存

见上面 malloc 示例。注意:free(NULL) 是安全的,什么都不做。

atoi(字符串) —— 字符串转 int

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    int num = atoi("12345");
    cout << "atoi(\"12345\") = " << num << endl;  // 12345
    int num2 = atoi("   -42abc");
    cout << "atoi(\"   -42abc\") = " << num2 << endl;  // -42(跳过前导空格,遇到非数字停止)
    return 0;
}

atof(字符串) —— 字符串转 double

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    double pi = atof("3.14159");
    cout << "atof(\"3.14159\") = " << pi << endl;  // 3.14159
    return 0;
}

atol(字符串) —— 字符串转 long

atoll(字符串) —— 字符串转 long long(C99)

strtol(字符串, &结束指针, 进制) —— 字符串转 long(更安全,可检测错误)

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    char str[] = "12345abc";
    char* end;
    long num = strtol(str, &end, 10);  // 10进制
    cout << "数字部分:" << num << endl;   // 12345
    cout << "剩余部分:" << end << endl;   // abc
    return 0;
}

strtod(字符串, &结束指针) —— 字符串转 double(更安全)

用法类似 strtol。

getenv("变量名") —— 获取环境变量值

#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    const char* path = getenv("PATH");
    if (path) {
        cout << "PATH = " << path << endl;
    }
    return 0;
}

qsort(数组, 个数, 大小, 比较函数) —— 快速排序

#include <cstdlib>
#include <iostream>
using namespace std;
int compare(const void* a, const void* b) {
    return *(int*)a - *(int*)b;  // 升序
}
int main() {
    int arr[] = {5, 2, 8, 1, 9, 3};
    int n = sizeof(arr) / sizeof(arr[0]);
    qsort(arr, n, sizeof(int), compare);
    for (int i = 0; i < n; i++) cout << arr[i] << " ";
    cout << endl;  // 1 2 3 5 8 9
    return 0;
}

exit(状态码) —— 正常终止程序(状态码0表示成功)

_Exit(状态码) —— 立即终止,不做清理(C99)

atexit(函数) —— 注册程序退出时调用的函数

⚠️ rand() 随机性不太好,C++11 推荐用 <random>。

5.3 <random> —— 高质量随机数(C++11)C++

是什么

📚 比 rand() 质量高得多,支持各种分布。

📚 两部分:随机数引擎(生成原始随机数)+ 分布(映射到想要的范围)

随机数引擎(每个附完整示例)

mt19937 / mt19937_64 —— 梅森旋转(最常用,32/64位)

#include <random>
#include <iostream>
using namespace std;
int main() {
    mt19937 rng(42);  // 用固定种子42创建引擎
    int r = rng();    // 生成一个随机数
    cout << "随机数:" << r << endl;
    return 0;
}

default_random_engine —— 默认引擎

#include <random>
#include <iostream>
using namespace std;
int main() {
    default_random_engine rng;
    cout << rng() << endl;
    return 0;
}

minstd_rand —— 线性同余

#include <random>
#include <iostream>
using namespace std;
int main() {
    minstd_rand rng;
    cout << rng() << endl;
    return 0;
}

random_device —— 真随机数(用于播种)

#include <random>
#include <iostream>
using namespace std;
int main() {
    random_device rd;
    mt19937 rng(rd());  // 用真随机数播种
    cout << rng() << endl;
    return 0;
}

随机数分布(每个附完整示例)

uniform_int_distribution<int> —— 均匀整数

#include <random>
#include <iostream>
using namespace std;
int main() {
    random_device rd;
    mt19937 rng(rd());
    uniform_int_distribution<int> dist(1, 6);  // 掷骰子
    int r = dist(rng);
    cout << "骰子点数:" << r << endl;
    return 0;
}

uniform_real_distribution<double> —— 均匀实数

#include <random>
#include <iostream>
using namespace std;
int main() {
    random_device rd;
    mt19937 rng(rd());
    uniform_real_distribution<double> dist(0.0, 1.0);
    double r = dist(rng);
    cout << "随机实数:" << r << endl;
    return 0;
}

normal_distribution<double> —— 正态分布

#include <random>
#include <iostream>
using namespace std;
int main() {
    random_device rd;
    mt19937 rng(rd());
    normal_distribution<double> dist(0, 1);  // 均值0,标准差1
    double r = dist(rng);
    cout << "正态分布随机数:" << r << endl;
    return 0;
}

bernoulli_distribution —— 伯努利(0或1)

#include <random>
#include <iostream>
using namespace std;
int main() {
    random_device rd;
    mt19937 rng(rd());
    bernoulli_distribution dist(0.5);  // 50%概率
    bool r = dist(rng);
    cout << "结果:" << (r ? "正面" : "反面") << endl;
    return 0;
}

poisson_distribution —— 泊松分布

#include <random>
#include <iostream>
using namespace std;
int main() {
    random_device rd;
    mt19937 rng(rd());
    poisson_distribution<int> dist(4.0);
    int r = dist(rng);
    cout << "泊松分布随机数:" << r << endl;
    return 0;
}

exponential_distribution —— 指数分布

#include <random>
#include <iostream>
using namespace std;
int main() {
    random_device rd;
    mt19937 rng(rd());
    exponential_distribution<double> dist(1.0);
    double r = dist(rng);
    cout << "指数分布随机数:" << r << endl;
    return 0;
}
#include <random>
#include <iostream>
using namespace std;
int main() {
    // 基本用法
    random_device rd;
    mt19937 rng(rd());                          // 用真随机数播种
    uniform_int_distribution<int> dist(1, 100); // 1~100均匀分布
    int r = dist(rng);                          // 生成随机数
    cout << "1~100随机数:" << r << endl;

    // 正态分布
    normal_distribution<double> ndist(0, 1);    // 均值0,标准差1
    double nr = ndist(rng);
    cout << "正态分布:" << nr << endl;
    return 0;
}

5.4 <complex> —— 复数C++

复数类,支持四则运算和数学函数。

#include <complex>
#include <iostream>
using namespace std;
int main() {
    complex<double> c1(3, 4);   // 3 + 4i
    complex<double> c2(1, 2);   // 1 + 2i
    auto c3 = c1 + c2;          // 4 + 6i
    cout << "c1=" << c1 << endl;
    cout << "c1+c2=" << c3 << endl;
    cout << "实部=" << c1.real() << endl;     // 3
    cout << "虚部=" << c1.imag() << endl;     // 4
    cout << "模=" << abs(c1) << endl;         // 5
    cout << "共轭=" << conj(c1) << endl;      // 3-4i
    return 0;
}

初学者一般用不到。

5.5 <limits> —— 类型极限值C++

是什么

📚 numeric_limits<T> 查询各种数据类型的极限值和特性。

📚 类比:一张"参数表",告诉你 int 最大能存多少、double 精度是多少。

常用成员(每个附完整示例)

numeric_limits<int>::max() —— int 最大值(约21亿)

#include <limits>
#include <iostream>
using namespace std;
int main() {
    int mx = numeric_limits<int>::max();
    cout << "int最大值:" << mx << endl;
    return 0;
}

numeric_limits<int>::min() —— int 最小值

#include <limits>
#include <iostream>
using namespace std;
int main() {
    int mn = numeric_limits<int>::min();
    cout << "int最小值:" << mn << endl;
    return 0;
}

numeric_limits<int>::lowest() —— 最低值

#include <limits>
#include <iostream>
using namespace std;
int main() {
    int lo = numeric_limits<int>::lowest();
    cout << "int最低值:" << lo << endl;
    return 0;
}

numeric_limits<double>::epsilon() —— 机器精度(约2.2e-16)

#include <limits>
#include <iostream>
using namespace std;
int main() {
    double eps = numeric_limits<double>::epsilon();
    cout << "double精度:" << eps << endl;
    return 0;
}

numeric_limits<int>::digits —— 二进制位数

#include <limits>
#include <iostream>
using namespace std;
int main() {
    int d = numeric_limits<int>::digits;  // 31
    cout << "int二进制位数:" << d << endl;
    return 0;
}

numeric_limits<int>::is_signed —— 是否有符号

#include <limits>
#include <iostream>
using namespace std;
int main() {
    bool s = numeric_limits<int>::is_signed;  // true
    cout << "int是否有符号:" << (s ? "是" : "否") << endl;
    return 0;
}

numeric_limits<int>::is_integer —— 是否整数类型

#include <limits>
#include <iostream>
using namespace std;
int main() {
    bool i = numeric_limits<int>::is_integer;  // true
    cout << "int是否整数:" << (i ? "是" : "否") << endl;
    return 0;
}

numeric_limits<double>::infinity() —— 正无穷

#include <limits>
#include <iostream>
using namespace std;
int main() {
    double inf = numeric_limits<double>::infinity();
    cout << "正无穷:" << inf << endl;
    return 0;
}

numeric_limits<double>::quiet_NaN() —— 非数

#include <limits>
#include <iostream>
using namespace std;
int main() {
    double nan = numeric_limits<double>::quiet_NaN();
    cout << "非数:" << nan << endl;
    return 0;
}
#include <limits>
#include <iostream>
using namespace std;
int main() {
    cout << "int最大:" << numeric_limits<int>::max() << endl;
    cout << "double精度:" << numeric_limits<double>::epsilon() << endl;
    return 0;
}

场景

- 初始化最值变量(找最大值时初始设为 min())

- 浮点数比较用 fabs(a-b) < epsilon,不要直接 ==

5.6 <ratio> —— 编译期有理数(C++11)C++

编译期表示分数,主要用于 <chrono> 时间单位定义。

初学者一般不直接用,知道存在即可。

#include <ratio>
#include <iostream>
using namespace std;
int main() {
    typedef ratio<1, 1000> milli;  // 1/1000
    cout << milli::num << "/" << milli::den << endl;  // 1/1000
    // 常用预定义:kilo(1000), mega(10^6), giga(10^9),
    //            milli(10^-3), micro(10^-6), nano(10^-9)
    return 0;
}
第六章 时间与日期

6.1 <chrono> —— 现代时间库(C++11)C++

是什么

📚 C++11 现代化时间库,比 C 的 time 函数好用且类型安全。

📚 三个核心概念:时钟(clock)、时长(duration)、时间点(time_point)。

时钟(每个附完整示例)

system_clock —— 系统时钟(可转日历时间)

#include <chrono>
#include <ctime>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main() {
    auto now = system_clock::now();
    time_t t = system_clock::to_time_t(now);
    cout << ctime(&t);
    return 0;
}

steady_clock —— 单调时钟(不受系统时间调整影响,适合计时)

#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main() {
    auto t0 = steady_clock::now();
    // ... 代码 ...
    auto t1 = steady_clock::now();
    cout << "耗时:" << duration_cast<microseconds>(t1-t0).count() << "微秒" << endl;
    return 0;
}

high_resolution_clock —— 高分辨率时钟

#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main() {
    auto t = high_resolution_clock::now();
    cout << "高分辨率时钟已获取" << endl;
    return 0;
}

时长(duration)

🎯 预定义类型: nanoseconds / microseconds / milliseconds seconds / minutes / hours

#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main() {
    seconds s(5);              // 5秒
    milliseconds ms(1000);     // 1000毫秒
    auto total = s + ms;       // 可加减
    cout << "总毫秒数:" << duration_cast<milliseconds>(total).count() << endl;
    return 0;
}

时间点(time_point)

表示某个时刻。

#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main() {
    auto tp = system_clock::now();  // 当前时间点
    auto tp2 = tp + seconds(10);    // 10秒后
    cout << "时间点已创建" << endl;
    return 0;
}

duration_cast —— 时长转换

#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main() {
    seconds s(2);
    auto ms = duration_cast<milliseconds>(s);  // 2000毫秒
    cout << ms.count() << endl;  // 输出 2000(count() 返回数值)
    return 0;
}
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main() {
    // 程序计时
    auto t0 = high_resolution_clock::now();
    // ... 执行一些代码 ...
    int sum = 0;
    for (int i = 0; i < 1000000; i++) sum += i;
    auto t1 = high_resolution_clock::now();
    cout << "耗时:" << duration_cast<microseconds>(t1-t0).count() << "微秒" << endl;
    return 0;
}
💡 C++20 增加了日历(year、month、day、date)和时区支持。

6.2 <ctime> —— C 风格时间C 兼容

常用函数(每个函数附完整示例)

time(&t) —— 当前时间(time_t,1970年至今秒数)

#include <ctime>
#include <iostream>
using namespace std;
int main() {
    time_t now = time(0);  // 或 time(&t);
    cout << "时间戳:" << now << endl;
    return 0;
}

clock() —— 程序CPU时间(用于计时)

#include <ctime>
#include <iostream>
using namespace std;
int main() {
    clock_t c0 = clock();
    // ... 代码 ...
    int sum = 0;
    for (int i = 0; i < 1000000; i++) sum += i;
    clock_t c1 = clock();
    double sec = (double)(c1-c0) / CLOCKS_PER_SEC;
    cout << "耗时:" << sec << "秒" << endl;
    return 0;
}

difftime(t1, t0) —— 时间差(秒)

#include <ctime>
#include <iostream>
using namespace std;
int main() {
    time_t t0 = time(0);
    // ... 一些操作 ...
    time_t t1 = time(0);
    double diff = difftime(t1, t0);
    cout << "时间差:" << diff << "秒" << endl;
    return 0;
}

localtime(&t) —— 转本地时间 struct tm

#include <ctime>
#include <iostream>
using namespace std;
int main() {
    time_t t = time(0);
    struct tm* lt = localtime(&t);
    cout << "年份:" << lt->tm_year + 1900 << endl;  // 年份
    cout << "月份:" << lt->tm_mon + 1 << endl;      // 月份
    return 0;
}

gmtime(&t) —— 转 UTC 时间 struct tm

#include <ctime>
#include <iostream>
using namespace std;
int main() {
    time_t t = time(0);
    struct tm* gt = gmtime(&t);
    cout << "UTC小时:" << gt->tm_hour << endl;
    return 0;
}

asctime(&tm) —— 转字符串

#include <ctime>
#include <iostream>
using namespace std;
int main() {
    time_t t = time(0);
    cout << asctime(localtime(&t));
    return 0;
}

ctime(&t) —— 直接转本地时间字符串

#include <ctime>
#include <iostream>
using namespace std;
int main() {
    time_t t = time(0);
    cout << ctime(&t);
    return 0;
}

strftime(buf,size,format,&tm) —— 格式化时间字符串

#include <ctime>
#include <iostream>
using namespace std;
int main() {
    time_t t = time(0);
    char buf[100];
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&t));
    // 格式:%Y年 %m月 %d日 %H时 %M分 %S秒
    cout << buf << endl;
    return 0;
}

struct tm 结构体

tm_year 年(从1900开始,要+1900)

tm_mon 月(0-11,要+1)

tm_mday 日(1-31)

tm_hour 时(0-23)

tm_min 分(0-59)

tm_sec 秒(0-60)

tm_wday 星期(0-6,0是周日)

#include <ctime>
#include <iostream>
using namespace std;
int main() {
    time_t now = time(0);
    cout << ctime(&now);  // 输出当前时间字符串
    return 0;
}

mktime(&tm结构) —— 将 tm 结构转为 time_t 时间戳(同时规范化tm结构)

#include <ctime>
#include <iostream>
using namespace std;
int main() {
    struct tm t = {};
    t.tm_year = 2024 - 1900;  // 年(从1900开始)
    t.tm_mon = 0;             // 月(0-11,0是1月)
    t.tm_mday = 1;            // 日(1-31)
    t.tm_hour = 12;
    t.tm_min = 0;
    t.tm_sec = 0;
    time_t timestamp = mktime(&t);
    cout << "2024年1月1日12:00的时间戳:" << timestamp << endl;
    cout << "对应时间:" << ctime(&timestamp);
    return 0;
}

difftime(时间1, 时间2) —— 计算两个时间差(秒)

见前面示例。

第七章 内存管理

7.1 <memory> —— 智能指针(C++11 重点!)C++

为什么需要智能指针

new 申请的内存必须 delete 释放,否则内存泄漏。

但人总会忘写 delete,或程序抛异常跳过了 delete。

智能指针能自动释放内存,类比"用完自动还书的借书证"。

unique_ptr<T> —— 独占所有权

🎯 一个对象只能被一个 unique_ptr 拥有,不能复制,只能移动。

📌 说明:

• 类比:独家代理权,只有你能卖这个产品。

#include <memory>
#include <iostream>
using namespace std;
int main() {
    unique_ptr<int> p = make_unique<int>(42);  // C++14
    cout << *p << endl;  // 42
    // 离开作用域自动 delete,不需手动释放
    // unique_ptr<int> p2 = p;        // 错误!不能复制
    unique_ptr<int> p3 = move(p);  // 可以移动,p变空
    cout << *p3 << endl;
    return 0;
}

shared_ptr<T> —— 共享所有权

🎯 多个 shared_ptr 可指向同一对象,用引用计数管理。

📌 说明:

• 每多一个指针计数+1,每少一个计数-1,计数归零自动释放。

• 类比:合租公寓,每人都有钥匙,最后走的人关灯锁门。

#include <memory>
#include <iostream>
using namespace std;
int main() {
    shared_ptr<int> p1 = make_shared<int>(42);
    shared_ptr<int> p2 = p1;        // 可以复制,计数变2
    cout << "引用计数:" << p1.use_count() << endl;  // 2
    // p1和p2都销毁时内存才释放
    return 0;
}

weak_ptr<T> —— 弱引用

🎯 不增加引用计数,只是"观察"对象。

📌 说明:

• 解决 shared_ptr 循环引用问题。

#include <memory>
#include <iostream>
using namespace std;
int main() {
    shared_ptr<int> sp = make_shared<int>(42);
    weak_ptr<int> wp = sp;           // 不增加计数
    cout << "引用计数:" << sp.use_count() << endl;  // 1
    if (auto p = wp.lock()) {        // 尝试升级为 shared_ptr
        cout << *p << endl;
    }
    return 0;
}

make_unique / make_shared —— 创建智能指针

🎯 推荐用这两个函数创建,不要直接用 new。

📌 说明:

• make_shared 更高效(一次分配内存)。

其他工具(每个附完整示例)

allocator<T> —— 内存分配器(底层,一般不直接用)

#include <memory>
#include <iostream>
using namespace std;
int main() {
    allocator<int> alloc;
    int* p = alloc.allocate(5);   // 分配5个int空间
    alloc.construct(p, 42);       // 在p上构造
    cout << *p << endl;
    alloc.destroy(p);             // 析构
    alloc.deallocate(p, 5);       // 释放
    return 0;
}

addressof(obj) —— 获取对象真实地址(即使重载了&)

#include <memory>
#include <iostream>
using namespace std;
int main() {
    int x = 5;
    int* p = addressof(x);  // p = &x
    cout << "地址:" << p << endl;
    return 0;
}

智能指针选择

独占所有权 → unique_ptr(默认首选,开销最小)

共享所有权 → shared_ptr

只是观察 → weak_ptr

7.2 <new> —— 内存分配原语C++

operator new / operator delete

底层内存分配/释放函数,new 表达式内部调用。一般不需直接调用。

#include <new>
#include <iostream>
using namespace std;
int main() {
    void* p = operator new(sizeof(int));  // 分配原始内存
    int* ip = new (p) int(42);            // placement new 构造
    cout << *ip << endl;
    ip->~int();                            // 析构
    operator delete(p);                    // 释放内存
    return 0;
}

placement new —— 在已分配内存上构造对象

#include <new>
#include <iostream>
using namespace std;
int main() {
    char buffer[sizeof(int)];
    int* p = new (buffer) int(42);  // 在 buffer 上构造 int
    cout << *p << endl;
    p->~int();  // 手动析构(placement new 需手动析构)
    return 0;
}

nothrow —— 不抛异常的 new

默认 new 失败抛 bad_alloc。nothrow 版失败返回 nullptr:

#include <new>
#include <iostream>
using namespace std;
int main() {
    int* p = new (nothrow) int[1000000];
    if (p == nullptr) {
        cout << "分配失败" << endl;
    } else {
        cout << "分配成功" << endl;
        delete[] p;
    }
    return 0;
}

bad_alloc —— 内存分配失败异常

第八章 多线程与并发(C++11 起)

多线程是什么

让程序同时做多件事。比如一边下载文件一边显示进度条。

类比:一个人(单线程)一件件做,多个人(多线程)同时做。

8.1 <thread> —— 线程C++

thread 类

创建新线程执行指定函数。

#include <thread>
#include <iostream>
using namespace std;
void hello() { cout << "Hello from thread!" << endl; }
int main() {
    thread t(hello);   // 创建线程执行 hello
    t.join();          // 等待线程执行完毕
    return 0;
}

常用方法(每个附完整示例)

join() —— 等待线程结束(阻塞当前线程)

#include <thread>
#include <iostream>
using namespace std;
void work() { cout << "工作中..." << endl; }
int main() {
    thread t(work);
    t.join();  // 等待线程结束
    cout << "线程已结束" << endl;
    return 0;
}

detach() —— 分离线程,后台自己运行(不等待)

#include <thread>
#include <iostream>
#include <chrono>
using namespace std;
void work() { cout << "后台工作..." << endl; }
int main() {
    thread t(work);
    t.detach();  // 分离线程
    this_thread::sleep_for(chrono::milliseconds(100));
    cout << "主线程继续" << endl;
    return 0;
}

joinable() —— 是否可以 join

#include <thread>
#include <iostream>
using namespace std;
void work() {}
int main() {
    thread t(work);
    if (t.joinable()) {
        cout << "可以join" << endl;
        t.join();
    }
    return 0;
}

get_id() —— 线程ID

#include <thread>
#include <iostream>
using namespace std;
void work() {}
int main() {
    thread t(work);
    cout << "线程ID:" << t.get_id() << endl;
    t.join();
    return 0;
}

传参给线程函数

#include <thread>
#include <iostream>
#include <string>
using namespace std;
void print(int x, string s) { cout << x << " " << s << endl; }
int main() {
    thread t(print, 42, "hello");  // 参数跟在函数名后面
    t.join();
    return 0;
}

this_thread 命名空间(每个附完整示例)

get_id() —— 当前线程ID

#include <thread>
#include <iostream>
using namespace std;
int main() {
    cout << "当前线程ID:" << this_thread::get_id() << endl;
    return 0;
}

yield() —— 让出CPU

#include <thread>
#include <iostream>
using namespace std;
int main() {
    this_thread::yield();
    cout << "已让出CPU" << endl;
    return 0;
}

sleep_for(100ms) —— 睡一段时间

#include <thread>
#include <chrono>
#include <iostream>
using namespace std;
int main() {
    cout << "开始睡眠..." << endl;
    this_thread::sleep_for(chrono::milliseconds(100));
    cout << "睡眠结束" << endl;
    return 0;
}

sleep_until(...) —— 睡到某个时间点

#include <thread>
#include <chrono>
#include <iostream>
using namespace std;
int main() {
    cout << "开始睡眠..." << endl;
    this_thread::sleep_until(chrono::system_clock::now() + chrono::seconds(1));
    cout << "睡眠结束" << endl;
    return 0;
}
⚠️ 创建了线程必须 join 或 detach,否则程序崩溃。

1. 多线程访问共享数据需要加锁(用 mutex)。

8.2 <mutex> —— 互斥锁C++

为什么需要锁

多线程同时修改同一变量会出问题(数据竞争)。

锁保证同一时间只有一个线程访问共享数据。

类比:公共厕所,一个人进去锁门,其他人等。

mutex —— 普通互斥锁

#include <mutex>
#include <iostream>
using namespace std;
int main() {
    mutex mtx;
    mtx.lock();      // 加锁(已被锁则等待)
    // 操作共享数据
    cout << "已加锁" << endl;
    mtx.unlock();    // 解锁
    return 0;
}

lock_guard —— 自动加解锁(推荐!)

构造时加锁,析构时自动解锁,不会忘记。

#include <mutex>
#include <iostream>
using namespace std;
int main() {
    mutex mtx;
    {
        lock_guard<mutex> lock(mtx);  // 加锁
        // 操作共享数据
        cout << "已加锁" << endl;
    }  // 离开作用域自动解锁
    cout << "已解锁" << endl;
    return 0;
}

unique_lock —— 更灵活的锁

🎯 可延迟加锁、手动解锁、转移所有权。

📌 说明:

• condition_variable 必须配合它。

#include <mutex>
#include <iostream>
using namespace std;
int main() {
    mutex mtx;
    unique_lock<mutex> lock(mtx);
    cout << "已加锁" << endl;
    lock.unlock();
    cout << "已解锁" << endl;
    lock.lock();
    cout << "再次加锁" << endl;
    return 0;
}

recursive_mutex —— 递归互斥锁

同一线程可多次加锁(不会死锁),解锁次数要对应。

#include <mutex>
#include <iostream>
using namespace std;
int main() {
    recursive_mutex mtx;
    mtx.lock();
    mtx.lock();   // 同一线程可再次加锁
    cout << "已加锁两次" << endl;
    mtx.unlock();
    mtx.unlock(); // 解锁两次才真正释放
    cout << "已完全解锁" << endl;
    return 0;
}

timed_mutex —— 可超时互斥锁

🎯 try_lock_for(100ms) 尝试加锁,最多等100毫秒。

#include <mutex>
#include <chrono>
#include <iostream>
using namespace std;
int main() {
    timed_mutex mtx;
    if (mtx.try_lock_for(chrono::milliseconds(100))) {
        // 成功加锁
        cout << "成功加锁" << endl;
        mtx.unlock();
    } else {
        // 超时,没拿到锁
        cout << "超时" << endl;
    }
    return 0;
}

scoped_lock(C++17)—— 多锁死锁安全

同时加多个锁,内部自动避免死锁:

#include <mutex>
#include <iostream>
using namespace std;
int main() {
    mutex mtx1, mtx2, mtx3;
    scoped_lock lock(mtx1, mtx2, mtx3);
    cout << "三个锁都已加锁" << endl;
    return 0;
}

8.3 <condition_variable> —— 条件变量C++

是什么

📚 让线程"等待某个条件成立",条件成立时被唤醒。

📚 比轮询更高效。

📚 类比:等外卖,不用每分钟去门口看,等外卖员打电话通知。

#include <condition_variable>
#include <mutex>
#include <thread>
#include <iostream>
using namespace std;

condition_variable cv;
mutex mtx;
bool ready = false;

void worker() {
    unique_lock<mutex> lock(mtx);
    cv.wait(lock, []{ return ready; });  // 等待 ready 变 true
    cout << "工作线程被唤醒" << endl;
}

int main() {
    thread t(worker);
    // 通知线程
    {
        lock_guard<mutex> lock(mtx);
        ready = true;
    }
    cv.notify_one();   // 唤醒一个等待线程
    // cv.notify_all(); // 唤醒所有
    t.join();
    return 0;
}
⚠️ wait 可能被虚假唤醒,一定要用带条件判断的版本(第二个参数)。

8.4 <future> —— 异步任务C++

是什么

📚 让任务在后台运行,以后再来取结果。

📚 类比:餐厅点菜给你取餐号(future),饭做好了凭号取。

async —— 异步执行函数

#include <future>
#include <iostream>
using namespace std;
int main() {
    future<int> f = async([]{ return 42; });  // 后台执行
    // ... 做其他事 ...
    int result = f.get();  // 取结果(没好会等待)
    cout << "结果:" << result << endl;
    return 0;
}

启动策略:

launch::async 立即在新线程执行

launch::deferred 延迟到 get() 时才执行(当前线程)

future<T> —— 异步结果(每个方法附完整示例)

get() —— 获取结果(只能调用一次!)

#include <future>
#include <iostream>
using namespace std;
int main() {
    future<int> f = async([]{ return 42; });
    int r = f.get();  // r = 42
    cout << "结果:" << r << endl;
    return 0;
}

wait() —— 等待就绪(不取)

#include <future>
#include <iostream>
using namespace std;
int main() {
    future<int> f = async([]{ return 42; });
    f.wait();
    cout << "已就绪" << endl;
    cout << f.get() << endl;
    return 0;
}

wait_for() —— 等待一段时间

#include <future>
#include <chrono>
#include <iostream>
using namespace std;
int main() {
    future<int> f = async([]{ return 42; });
    auto status = f.wait_for(chrono::seconds(1));
    if (status == future_status::ready) cout << "好了" << endl;
    cout << f.get() << endl;
    return 0;
}

valid() —— 是否有效

#include <future>
#include <iostream>
using namespace std;
int main() {
    future<int> f = async([]{ return 42; });
    if (f.valid()) cout << "有效" << endl;
    cout << f.get() << endl;
    return 0;
}

promise<T> —— 手动设置结果

比 async 更底层,可手动控制何时设结果。

#include <future>
#include <thread>
#include <iostream>
using namespace std;
int main() {
    promise<int> p;
    future<int> f = p.get_future();
    // 另一个线程:p.set_value(42);
    thread t([&p]{ p.set_value(42); });
    int r = f.get();
    cout << "结果:" << r << endl;
    t.join();
    return 0;
}

packaged_task —— 打包任务

把函数包装起来,方便传给线程执行。

#include <future>
#include <thread>
#include <iostream>
using namespace std;
int main() {
    packaged_task<int()> task([]{ return 42; });
    future<int> f = task.get_future();
    thread t(move(task));
    int r = f.get();
    cout << "结果:" << r << endl;
    t.join();
    return 0;
}

8.5 <atomic> —— 原子操作C++

是什么

📚 原子类型的操作"不可分割",多线程同时访问也不会出问题,不需加锁。

📚 类比:自动售货机,投币和出货一体,不会两人同时抢到同一瓶。

atomic<T> —— 原子类型

#include <atomic>
#include <iostream>
using namespace std;
int main() {
    atomic<int> counter(0);
    counter++;              // 原子自增,多线程安全
    int x = counter;        // 原子读取
    counter.store(10);      // 原子写入
    cout << "counter=" << counter << endl;
    return 0;
}

常用操作(每个附完整示例)

load() —— 读取

#include <atomic>
#include <iostream>
using namespace std;
int main() {
    atomic<int> a(0);
    int x = a.load();
    cout << "x=" << x << endl;
    return 0;
}

store(x) —— 写入

#include <atomic>
#include <iostream>
using namespace std;
int main() {
    atomic<int> a(0);
    a.store(10);
    cout << "a=" << a << endl;
    return 0;
}

exchange(x) —— 写入并返回旧值

#include <atomic>
#include <iostream>
using namespace std;
int main() {
    atomic<int> a(10);
    int old = a.exchange(20);  // old=10, a=20
    cout << "old=" << old << ", a=" << a << endl;
    return 0;
}

fetch_add(x) / fetch_sub(x) —— 加/减并返回旧值

#include <atomic>
#include <iostream>
using namespace std;
int main() {
    atomic<int> a(20);
    int old = a.fetch_add(5);  // old=20, a=25
    int old2 = a.fetch_sub(3); // old2=25, a=22
    cout << "old=" << old << ", old2=" << old2 << ", a=" << a << endl;
    return 0;
}

compare_exchange_weak/strong —— 比较并交换(CAS)

#include <atomic>
#include <iostream>
using namespace std;
int main() {
    atomic<int> a(22);
    int expected = 22;
    bool ok = a.compare_exchange_strong(expected, 99);
    // 如果 a==expected,则 a=99,返回true
    // 否则 expected=a,返回false
    cout << "ok=" << ok << ", a=" << a << endl;
    return 0;
}

预定义类型:atomic_bool、atomic_int、atomic_long 等

内存序(高级,初学者先忽略)

memory_order_relaxed / acquire / release / seq_cst

默认 seq_cst(最强保证,最慢),一般用默认。

场景:简单计数器、标志位用 atomic(比 mutex 快);复杂操作用 mutex。

8.6 <shared_mutex> —— 读写锁(C++14/17)C++

是什么

📚 多线程可同时读,但写时独占。

📚 读多写少场景比 mutex 性能好。

📚 类比:图书馆,多人可同时看书(读),整理书架(写)时其他人不能进。

shared_mutex mtx;

// 读操作:共享锁(多个线程可同时持有)

{

shared_lock<shared_mutex> lock(mtx);

// 读取共享数据

}

// 写操作:独占锁(只有一个线程能持有)

{

unique_lock<shared_mutex> lock(mtx);

// 修改共享数据

}

常用方法(每个附完整示例)

lock() / unlock() —— 独占加锁/解锁

#include <shared_mutex>
#include <iostream>
using namespace std;
int main() {
    shared_mutex mtx;
    mtx.lock();
    cout << "独占加锁" << endl;
    mtx.unlock();
    cout << "已解锁" << endl;
    return 0;
}

lock_shared() / unlock_shared() —— 共享加锁/解锁

#include <shared_mutex>
#include <iostream>
using namespace std;
int main() {
    shared_mutex mtx;
    mtx.lock_shared();
    cout << "共享加锁" << endl;
    mtx.unlock_shared();
    cout << "已解锁" << endl;
    return 0;
}

try_lock() / try_lock_shared() —— 尝试加锁

#include <shared_mutex>
#include <iostream>
using namespace std;
int main() {
    shared_mutex mtx;
    if (mtx.try_lock()) {
        cout << "成功加锁" << endl;
        mtx.unlock();
    }
    return 0;
}
第九章 函数对象与泛型编程

9.1 <functional> —— 函数包装与绑定C++

function<T> —— 可调用对象包装器

🎯 把函数、lambda、函数对象统一包装。

📌 说明:

• 类比:万能插座,什么插头都能插。

• T 格式:返回值类型(参数类型...)

#include <functional>
#include <iostream>
using namespace std;
int main() {
    function<int(int, int)> add = [](int a, int b){ return a+b; };
    cout << add(3, 4) << endl;  // 7
    return 0;
}

bind —— 绑定参数

固定部分参数生成新函数。

#include <functional>
#include <iostream>
using namespace std;
using namespace placeholders;
int add(int a, int b) { return a + b; }
int main() {
    auto add5 = bind(add, 5, _1);  // 固定第一个参数为5
    cout << add5(3) << endl;  // 8(相当于 add(5, 3))
    return 0;
}

placeholders::_1 表示"第一个参数留到以后传"。

💡 C++11 后 lambda 基本可替代 bind,bind 用得少了。

ref / cref —— 引用包装

🎯 把变量包装成引用,用于需要拷贝的场合(bind、thread 传参)。

#include <functional>
#include <thread>
#include <iostream>
using namespace std;
int main() {
    int x = 0;
    auto f = [](int& r){ r++; };
    thread t(f, ref(x));  // 用 ref 才能传引用
    t.join();
    cout << "x=" << x << endl;  // 1
    return 0;
}

预定义函数对象

🎯 算术:plus、minus、multiplies、divides、modulus、negate 比较:equal_to、not_equal_to、greater、less、greater_equal、less_equal 逻辑:logical_and、logical_or、logical_not

#include <functional>
#include <algorithm>
#include <numeric>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {3, 1, 4, 1, 5};
    sort(v.begin(), v.end(), greater<int>());          // 降序
    int sum = accumulate(v.begin(), v.end(), 0, plus<int>());    // 求和
    for (int x : v) cout << x << " ";
    cout << endl << "sum=" << sum << endl;
    return 0;
}

mem_fn —— 成员函数转函数对象

#include <functional>
#include <iostream>
using namespace std;
struct Foo { void bar() { cout << "bar" << endl; } };
int main() {
    Foo f;
    auto fn = mem_fn(&Foo::bar);
    fn(&f);  // 调用 f.bar()
    return 0;
}

9.2 <type_traits> —— 类型特征(C++11)C++

是什么

📚 编译期查询类型信息或变换类型。

📚 模板编程大量使用,初学者先了解。

类型判断(编译期返回 true/false,每个附完整示例)

is_integral<T> —— 整数类型

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    bool b = is_integral<int>::value;  // true
    cout << "int是整数:" << (b ? "是" : "否") << endl;
    return 0;
}

is_floating_point<T> —— 浮点类型

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    bool b = is_floating_point<double>::value;  // true
    cout << "double是浮点:" << (b ? "是" : "否") << endl;
    return 0;
}

is_arithmetic<T> —— 算术类型(整数或浮点)

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    bool b = is_arithmetic<int>::value;  // true
    cout << "int是算术类型:" << (b ? "是" : "否") << endl;
    return 0;
}

is_signed<T> / is_unsigned<T> —— 有/无符号

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    bool b1 = is_signed<int>::value;   // true
    bool b2 = is_unsigned<unsigned>::value;  // true
    cout << "int有符号:" << (b1 ? "是" : "否") << endl;
    cout << "unsigned无符号:" << (b2 ? "是" : "否") << endl;
    return 0;
}

is_pointer<T> —— 指针

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    bool b = is_pointer<int*>::value;  // true
    cout << "int*是指针:" << (b ? "是" : "否") << endl;
    return 0;
}

is_reference<T> —— 引用

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    bool b = is_reference<int&>::value;  // true
    cout << "int&是引用:" << (b ? "是" : "否") << endl;
    return 0;
}

is_array<T> —— 数组

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    bool b = is_array<int[5]>::value;  // true
    cout << "int[5]是数组:" << (b ? "是" : "否") << endl;
    return 0;
}

is_class<T> —— 类

#include <type_traits>
#include <string>
#include <iostream>
using namespace std;
int main() {
    bool b = is_class<string>::value;  // true
    cout << "string是类:" << (b ? "是" : "否") << endl;
    return 0;
}

is_enum<T> —— 枚举

#include <type_traits>
#include <iostream>
using namespace std;
enum E { A };
int main() {
    bool b = is_enum<E>::value;  // true
    cout << "E是枚举:" << (b ? "是" : "否") << endl;
    return 0;
}

is_const<T> —— const

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    bool b = is_const<const int>::value;  // true
    cout << "const int是const:" << (b ? "是" : "否") << endl;
    return 0;
}

is_same<T,U> —— T和U同一类型

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    bool b = is_same<int, int>::value;  // true
    cout << "int和int相同:" << (b ? "是" : "否") << endl;
    return 0;
}

is_base_of<B,D> —— B是D的基类

#include <type_traits>
#include <iostream>
using namespace std;
class Base {};
class Derived : public Base {};
int main() {
    bool b = is_base_of<Base, Derived>::value;  // true
    cout << "Base是Derived的基类:" << (b ? "是" : "否") << endl;
    return 0;
}

is_convertible<F,T> —— F能转成T

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    bool b = is_convertible<int, double>::value;  // true
    cout << "int能转double:" << (b ? "是" : "否") << endl;
    return 0;
}

is_constructible<T,Args...> —— T能用Args构造

#include <type_traits>
#include <string>
#include <iostream>
using namespace std;
int main() {
    bool b = is_constructible<string, const char*>::value;  // true
    cout << "string能用const char*构造:" << (b ? "是" : "否") << endl;
    return 0;
}

类型变换(编译期返回新类型,每个附完整示例)

remove_const / add_const —— 去掉/加上 const

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    remove_const<const int>::type a = 5;  // a 是 int
    add_const<int>::type b = 10;           // b 是 const int
    cout << "a=" << a << ", b=" << b << endl;
    return 0;
}

remove_reference / add_lvalue_reference —— 去掉/加左值引用

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    int x = 5;
    remove_reference<int&>::type a = x;  // a 是 int
    add_lvalue_reference<int>::type b = x;  // b 是 int&
    cout << "a=" << a << ", b=" << b << endl;
    return 0;
}

remove_pointer / add_pointer —— 去掉/加指针

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    int x = 5;
    remove_pointer<int*>::type a = x;  // a 是 int
    add_pointer<int>::type b = &x;      // b 是 int*
    cout << "a=" << a << ", *b=" << *b << endl;
    return 0;
}

make_signed / make_unsigned —— 转有/无符号

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    make_signed<unsigned>::type a = -5;  // a 是 int
    make_unsigned<int>::type b = 10;     // b 是 unsigned
    cout << "a=" << a << ", b=" << b << endl;
    return 0;
}

decay<T> —— 退化(数组转指针等)

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    int arr[5] = {1,2,3,4,5};
    decay<int[5]>::type a = arr;  // a 是 int*
    cout << "*a=" << *a << endl;
    return 0;
}

common_type<T,U> —— 公共类型

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    common_type<int, double>::type a = 3.14;  // a 是 double
    cout << "a=" << a << endl;
    return 0;
}

conditional<Cond,T,F> —— 条件选择类型

#include <type_traits>
#include <iostream>
using namespace std;
int main() {
    conditional<true, int, double>::type a = 5;  // a 是 int
    cout << "a=" << a << endl;
    return 0;
}

enable_if —— SFINAE 核心工具

根据条件决定函数是否参与重载解析。

#include <type_traits>
#include <string>
#include <iostream>
using namespace std;
template<typename T>
typename enable_if<is_integral<T>::value, string>::type
describe(T x) { return "整数"; }
int main() {
    cout << describe(42) << endl;  // 整数
    return 0;
}

这个函数只对整数类型生效。

初学者先记住名字,写模板时再深入。

9.3 <utility> —— 通用工具C++

pair<T1,T2> —— 键值对

把两个值绑在一起。

#include <utility>
#include <string>
#include <iostream>
using namespace std;
int main() {
    pair<string, int> p("Tom", 20);
    cout << p.first << endl;   // "Tom"
    cout << p.second << endl;  // 20
    auto p2 = make_pair("Alice", 18);  // 自动推导类型
    cout << p2.first << " " << p2.second << endl;
    return 0;
}

move —— 移动语义

🎯 把左值转成右值引用,触发移动构造/赋值。

📌 说明:

• 类比:把对象资源"转让"给另一个对象,而不是拷贝。

#include <utility>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v1 = {1,2,3};
    vector<int> v2 = move(v1);  // v1资源转给v2,v1变空
    for (int x : v2) cout << x << " ";
    cout << endl;
    cout << "v1大小:" << v1.size() << endl;  // 0
    return 0;
}

forward<T> —— 完美转发

保持参数值类别(左值/右值)转发给另一个函数。主要用于模板。

#include <utility>
#include <iostream>
using namespace std;
template<typename T, typename U>
auto make_pair2(T&& a, U&& b) {
    return pair<decay_t<T>, decay_t<U>>(
        forward<T>(a), forward<U>(b));
}
int main() {
    auto p = make_pair2(10, "hello");
    cout << p.first << " " << p.second << endl;
    return 0;
}

swap —— 交换两个变量或容器

#include <utility>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    int a=1, b=2;
    swap(a, b);  // a=2, b=1
    cout << "a=" << a << ", b=" << b << endl;
    vector<int> v1={1,2}, v2={3,4};
    swap(v1, v2);
    for (int x : v1) cout << x << " ";
    cout << endl;
    return 0;
}

exchange(C++14)—— 替换并返回旧值

#include <utility>
#include <iostream>
using namespace std;
int main() {
    int x = 5;
    int old = exchange(x, 10);  // x变10,old=5
    cout << "old=" << old << ", x=" << x << endl;
    return 0;
}

declval<T> —— 生成右值引用,用于 decltype 表达式

#include <utility>
#include <string>
#include <iostream>
using namespace std;
int main() {
    // 不实际构造对象,只用于编译期类型推导
    using type = decltype(declval<string>().size());
    // type 是 size_t
    cout << "size_t大小:" << sizeof(type) << endl;
    return 0;
}

9.4 <tuple> —— 元组(C++11)C++

是什么

📚 pair 的扩展,可装任意多个、任意类型的值。

📚 类比:可装不同类型东西的"多格收纳盒"。

#include <tuple>
#include <string>
#include <iostream>
using namespace std;
int main() {
    tuple<int, string, double> t(20, "Tom", 95.5);
    cout << get<0>(t) << endl;   // 20
    cout << get<1>(t) << endl;   // "Tom"
    cout << get<2>(t) << endl;   // 95.5
    // C++14 可用类型获取(类型不重复时)
    cout << get<string>(t) << endl;  // "Tom"
    return 0;
}

辅助函数(每个附完整示例)

make_tuple(...) —— 创建元组(自动推导类型)

#include <tuple>
#include <string>
#include <iostream>
using namespace std;
int main() {
    auto t = make_tuple(20, "Tom", 95.5);
    cout << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << endl;
    return 0;
}

tie(...) —— 变量绑成引用,用于解包

#include <tuple>
#include <string>
#include <iostream>
using namespace std;
int main() {
    auto t = make_tuple(20, "Tom", 95.5);
    int a; string b; double c;
    tie(a, b, c) = t;  // 解包到变量
    cout << a << " " << b << " " << c << endl;
    return 0;
}

tuple_cat(...) —— 拼接多个元组

#include <tuple>
#include <string>
#include <iostream>
using namespace std;
int main() {
    auto t1 = make_tuple(1, 2);
    auto t2 = make_tuple("a", "b");
    auto t3 = tuple_cat(t1, t2);  // {1,2,"a","b"}
    cout << get<0>(t3) << " " << get<1>(t3) << " "
         << get<2>(t3) << " " << get<3>(t3) << endl;
    return 0;
}

解包

#include <tuple>
#include <string>
#include <iostream>
using namespace std;
int main() {
    auto t = make_tuple(20, "Tom", 95.5);
    // C++17 结构化绑定
    auto [age, name, score] = t;
    cout << age << " " << name << " " << score << endl;
    // C++11 方式
    int a; string b; double c;
    tie(a, b, c) = t;
    cout << a << " " << b << " " << c << endl;
    return 0;
}

场景:函数需返回多个值时(比定义结构体方便)

9.5 <variant> —— 类型安全联合体(C++17)C++

是什么

📚 同一位置可存不同类型,但同一时间只存一种。

📚 类比:"百变盒子",今天装int,明天装string,但只能装一个。

📚 比 C 的 union 安全(会记住当前存的类型)。

#include <variant>
#include <string>
#include <iostream>
using namespace std;
int main() {
    variant<int, string, double> v;
    v = 42;                     // 现在存int
    cout << get<int>(v) << endl;        // 42
    v = "hello";                // 现在存string
    cout << get<string>(v) << endl;     // "hello"

    // 安全访问
    if (holds_alternative<int>(v))
        cout << get<int>(v) << endl;

    // visit 处理所有可能类型
    visit([](auto&& x){ cout << x << endl; }, v);
    return 0;
}
⚠️ get<类型>() 类型不对会抛 bad_variant_access。

9.6 <any> —— 任意类型容器(C++17)C++

是什么

📚 可存任意类型的单个值。

📚 类比:"万能盒子",什么都能装,但取时要知道装的是什么。

#include <any>
#include <string>
#include <iostream>
using namespace std;
int main() {
    any a;
    a = 42;
    a = string("hello");
    a = 3.14;
    if (a.type() == typeid(int))
        cout << any_cast<int>(a) << endl;
    cout << "有值:" << a.has_value() << endl;  // 是否有值
    a.reset();              // 清空
    cout << "有值:" << a.has_value() << endl;
    return 0;
}

常用方法(每个附完整示例)

has_value() —— 是否有值

#include <any>
#include <iostream>
using namespace std;
int main() {
    any a = 42;
    if (a.has_value()) cout << "有值" << endl;
    return 0;
}

type() —— 当前值的类型

#include <any>
#include <iostream>
using namespace std;
int main() {
    any a = 42;
    cout << a.type().name() << endl;
    return 0;
}

any_cast<T>(a) —— 转换为指定类型(失败抛 bad_any_cast)

#include <any>
#include <iostream>
using namespace std;
int main() {
    any a = 42;
    int x = any_cast<int>(a);
    cout << "x=" << x << endl;
    return 0;
}

reset() —— 清空

#include <any>
#include <iostream>
using namespace std;
int main() {
    any a = 42;
    a.reset();
    cout << "有值:" << a.has_value() << endl;
    return 0;
}

和 variant 区别:variant 限定可存类型列表,any 不限。

variant 更安全高效,优先用 variant。

9.7 <optional> —— 可选值(C++17)C++

是什么

📚 optional<T> 表示"可能有一个T,也可能没有"。

📚 类比:"可能装了东西也可能空着的盒子"。

📚 常用于函数返回:找到了返回值,没找到返回空。

#include <optional>
#include <iostream>
using namespace std;
optional<int> find_number(int x) {
    if (x > 0) return x;
    return nullopt;  // 没有值
}
int main() {
    auto result = find_number(5);
    if (result) {                // 有值
        cout << *result << endl;         // 5
        cout << result.value() << endl;  // 5
    }
    cout << result.value_or(0) << endl;  // 有值返回值,没值返回0
    return 0;
}

常用方法(每个附完整示例)

optional<int> opt = 42;

has_value() / operator bool() —— 是否有值

#include <optional>
#include <iostream>
using namespace std;
int main() {
    optional<int> opt = 42;
    if (opt.has_value()) cout << "有值" << endl;
    if (opt) cout << "有值" << endl;  // 同上
    return 0;
}

value() —— 获取值(没值抛 bad_optional_access)

#include <optional>
#include <iostream>
using namespace std;
int main() {
    optional<int> opt = 42;
    int x = opt.value();
    cout << "x=" << x << endl;
    return 0;
}

operator*() / operator->() —— 访问值(不检查)

#include <optional>
#include <iostream>
using namespace std;
int main() {
    optional<int> opt = 42;
    int x = *opt;
    cout << "x=" << x << endl;
    return 0;
}

value_or(default) —— 有值返回值,没值返回默认值

#include <optional>
#include <iostream>
using namespace std;
int main() {
    optional<int> opt = nullopt;
    int x = opt.value_or(0);
    cout << "x=" << x << endl;
    return 0;
}

reset() —— 清空

#include <optional>
#include <iostream>
using namespace std;
int main() {
    optional<int> opt = 42;
    opt.reset();
    cout << "有值:" << opt.has_value() << endl;
    return 0;
}

好处:比用特殊值(如-1表示没找到)更清晰安全。

第十章 异常处理

异常是什么

程序运行出错时可"抛出"异常,在某个地方"捕获"处理。

类比:工作中遇到解决不了的问题,"上报"给上级处理。

10.1 <exception> —— 异常基类C++

exception —— 所有标准异常的基类

what() 返回异常描述字符串。

#include <exception>
#include <iostream>
using namespace std;
int main() {
    try {
        // 可能抛异常的代码
        throw runtime_error("出错了");
    } catch (const exception& e) {
        cout << "出错了:" << e.what() << endl;
    }
    return 0;
}

其他(每个附完整示例)

bad_exception —— unexpected 处理时抛出

#include <exception>
#include <iostream>
using namespace std;
int main() {
    // 一般不直接使用,由异常规范机制触发
    cout << "bad_exception一般不直接使用" << endl;
    return 0;
}

terminate() —— 异常未被捕获时调用,默认终止程序

#include <exception>
#include <iostream>
using namespace std;
int main() {
    // 未捕获的异常会自动调用 terminate()
    cout << "未捕获的异常会自动调用terminate()" << endl;
    return 0;
}

set_terminate() —— 设置自定义 terminate 处理函数

#include <exception>
#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
    set_terminate([]{ cout << "未捕获异常!" << endl; abort(); });
    cout << "已设置自定义terminate处理函数" << endl;
    return 0;
}

10.2 <stdexcept> —— 标准异常类C++

逻辑错误(logic_error 派生)—— 程序员的锅,可以避免(每个附完整示例)

invalid_argument —— 无效参数

#include <stdexcept>
#include <iostream>
using namespace std;
int main() {
    try {
        throw invalid_argument("参数不能为负");
    } catch (const exception& e) {
        cout << e.what() << endl;
    }
    return 0;
}

domain_error —— 定义域错误(如对负数开平方)

#include <stdexcept>
#include <iostream>
using namespace std;
int main() {
    try {
        throw domain_error("负数不能开平方");
    } catch (const exception& e) {
        cout << e.what() << endl;
    }
    return 0;
}

length_error —— 长度错误

#include <stdexcept>
#include <iostream>
using namespace std;
int main() {
    try {
        throw length_error("字符串太长");
    } catch (const exception& e) {
        cout << e.what() << endl;
    }
    return 0;
}

out_of_range —— 越界(如 vector.at() 下标超范围)

#include <stdexcept>
#include <iostream>
using namespace std;
int main() {
    try {
        throw out_of_range("下标越界");
    } catch (const exception& e) {
        cout << e.what() << endl;
    }
    return 0;
}

运行时错误(runtime_error 派生)—— 运行时才知道(每个附完整示例)

runtime_error —— 通用运行时错误

#include <stdexcept>
#include <iostream>
using namespace std;
int main() {
    try {
        throw runtime_error("运行时错误");
    } catch (const exception& e) {
        cout << e.what() << endl;
    }
    return 0;
}

range_error —— 范围错误

#include <stdexcept>
#include <iostream>
using namespace std;
int main() {
    try {
        throw range_error("结果超出范围");
    } catch (const exception& e) {
        cout << e.what() << endl;
    }
    return 0;
}

overflow_error —— 上溢

#include <stdexcept>
#include <iostream>
using namespace std;
int main() {
    try {
        throw overflow_error("整数溢出");
    } catch (const exception& e) {
        cout << e.what() << endl;
    }
    return 0;
}

underflow_error —— 下溢

#include <stdexcept>
#include <iostream>
using namespace std;
int main() {
    try {
        throw underflow_error("浮点数下溢");
    } catch (const exception& e) {
        cout << e.what() << endl;
    }
    return 0;
}
#include <stdexcept>
#include <cmath>
#include <iostream>
using namespace std;
double sqrt_safe(double x) {
    if (x < 0) throw domain_error("负数不能开平方");
    return sqrt(x);
}
int main() {
    try {
        cout << sqrt_safe(-1) << endl;
    } catch (const exception& e) {
        cout << e.what() << endl;
    }
    return 0;
}
#include <stdexcept>
#include <string>
#include <iostream>
using namespace std;
class MyError : public runtime_error {
public:
    MyError(const string& msg) : runtime_error(msg) {}
};
int main() {
    try {
        throw MyError("自定义错误");
    } catch (const exception& e) {
        cout << e.what() << endl;
    }
    return 0;
}

10.3 <system_error> —— 系统错误(C++11)C++

操作系统相关错误(文件操作、线程等)。

包含 error_code、error_condition、error_category、system_error。

初学者遇到时再查。

#include <system_error>
#include <iostream>
using namespace std;
int main() {
    try {
        throw system_error(make_error_code(errc::no_such_file_or_directory));
    } catch (const system_error& e) {
        cout << e.what() << endl;      // 错误描述
        cout << e.code() << endl;      // error_code
    }
    return 0;
}
第十一章 类型信息(RTTI)

11.1 <typeinfo> —— 运行时类型识别C++

typeid —— 获取类型信息

#include <typeinfo>
#include <iostream>
using namespace std;
int main() {
    int x = 5;
    cout << typeid(x).name() << endl;   // 类型名(如 "int",格式依编译器)
    if (typeid(x) == typeid(int)) {
        cout << "x是int类型" << endl;
    }
    return 0;
}

type_info 类(每个方法附完整示例)

name() —— 类型名(实现相关,不保证可读)

#include <typeinfo>
#include <iostream>
using namespace std;
int main() {
    cout << typeid(int).name() << endl;
    return 0;
}

before() —— 类型排序比较

#include <typeinfo>
#include <iostream>
using namespace std;
int main() {
    if (typeid(int).before(typeid(double)))
        cout << "int在前" << endl;
    return 0;
}

hash_code() —— 类型哈希值(C++11)

#include <typeinfo>
#include <iostream>
using namespace std;
int main() {
    size_t h = typeid(int).hash_code();
    cout << "哈希值:" << h << endl;
    return 0;
}

异常

bad_cast —— dynamic_cast 失败时抛出

#include <typeinfo>
#include <iostream>
using namespace std;
int main() {
    // dynamic_cast 引用失败时抛出 bad_cast
    cout << "dynamic_cast引用失败时抛出bad_cast" << endl;
    return 0;
}

bad_typeid —— 对空指针解引用后用 typeid

#include <typeinfo>
#include <iostream>
using namespace std;
int main() {
    // typeid(*nullptr) 会抛出 bad_typeid
    cout << "typeid(*nullptr)会抛出bad_typeid" << endl;
    return 0;
}
⚠️ typeid 的 name() 返回字符串不标准,GCC 下可能是 "i"、"NSt7..." 等不太可读。
第十二章 正则表达式(C++11)

12.1 <regex> —— 正则表达式C++

是什么

📚 正则表达式是"文本匹配模式",用来查找、替换、验证字符串。

📚 类比:高级搜索框,用规则描述"我要找什么样的文字"。

regex —— 正则表达式对象

#include <regex>
#include <string>
#include <iostream>
using namespace std;
int main() {
    regex pattern("\\d+");  // 匹配一个或多个数字
    cout << "正则表达式已创建" << endl;
    return 0;
}
⚠️ C++字符串中 \ 要写成 \\,或用原始字符串 R"(\d+)"

regex_match —— 整个字符串是否匹配

#include <regex>
#include <string>
#include <iostream>
using namespace std;
int main() {
    regex email_pattern(R"([\w.]+@[\w.]+\.\w+)");
    if (regex_match("test@example.com", email_pattern))
        cout << "是邮箱" << endl;
    return 0;
}

regex_search —— 搜索匹配(只要有一部分匹配就行)

#include <regex>
#include <string>
#include <iostream>
using namespace std;
int main() {
    string text = "电话:12345678";
    smatch match;
    if (regex_search(text, match, regex(R"(\d+)")))
        cout << match.str() << endl;  // "12345678"
    return 0;
}

regex_replace —— 替换匹配

#include <regex>
#include <string>
#include <iostream>
using namespace std;
int main() {
    string text = "2026-08-12";
    string result = regex_replace(text, regex("-"), "/");
    // result = "2026/08/12"
    cout << result << endl;
    return 0;
}

smatch —— 匹配结果(每个方法附完整示例)

match.str() —— 整个匹配字符串

#include <regex>
#include <string>
#include <iostream>
using namespace std;
int main() {
    smatch match;
    regex_search("abc123", match, regex(R"((\w+)(\d+))"));
    cout << match.str() << endl;  // "abc123"
    return 0;
}

match[0] —— 第0个捕获组(整个匹配)

#include <regex>
#include <string>
#include <iostream>
using namespace std;
int main() {
    smatch match;
    regex_search("abc123", match, regex(R"((\w+)(\d+))"));
    cout << match[0].str() << endl;  // "abc123"
    return 0;
}

match[1] —— 第1个捕获组

#include <regex>
#include <string>
#include <iostream>
using namespace std;
int main() {
    smatch match;
    regex_search("abc123", match, regex(R"((\w+)(\d+))"));
    cout << match[1].str() << endl;  // "abc"
    return 0;
}

match.position() —— 匹配位置

#include <regex>
#include <string>
#include <iostream>
using namespace std;
int main() {
    smatch match;
    regex_search("abc123", match, regex(R"((\w+)(\d+))"));
    cout << match.position() << endl;  // 0
    return 0;
}

找所有匹配(迭代器)

#include <regex>
#include <string>
#include <iostream>
using namespace std;
int main() {
    string text = "a1 b2 c3";
    regex pattern(R"(\w\d)");
    sregex_iterator it(text.begin(), text.end(), pattern);
    sregex_iterator end;
    for (; it != end; ++it) cout << it->str() << endl;
    return 0;
}

常用正则语法

语法 含义

\d 数字

\w 字母数字下划线

\s 空白字符

. 任意字符

* 0次或多次

+ 1次或多次

? 0次或1次

{n} 恰好n次

{n,m} n到m次

^ 开头

$ 结尾

[] 字符集合

() 捕获组

| 或

第十三章 文件系统(C++17)

13.1 <filesystem> —— 文件系统操作C++

是什么

📚 C++17 终于有了标准文件系统库,可跨平台操作文件和目录。

📚 之前只能用平台相关 API(Windows <windows.h> 或 Linux <unistd.h>)。

path —— 文件路径

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::path p = "C:/Users/test/Desktop/file.txt";
    cout << p.filename() << endl;     // "file.txt"
    cout << p.extension() << endl;    // ".txt"
    cout << p.parent_path() << endl;  // "C:/Users/test/Desktop"
    cout << p.stem() << endl;         // "file"
    p /= "subdir";            // 拼接路径
    cout << p << endl;
    return 0;
}

文件信息查询(每个附完整示例)

namespace fs = filesystem;

exists(p) —— 是否存在

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::path p = "test.txt";
    if (fs::exists(p)) cout << "存在" << endl;
    else cout << "不存在" << endl;
    return 0;
}

is_directory(p) —— 是否目录

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::path p = ".";
    if (fs::is_directory(p)) cout << "是目录" << endl;
    return 0;
}

is_regular_file(p) —— 是否普通文件

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::path p = "test.txt";
    if (fs::is_regular_file(p)) cout << "是文件" << endl;
    return 0;
}

is_symlink(p) —— 是否符号链接

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::path p = "link";
    if (fs::is_symlink(p)) cout << "是符号链接" << endl;
    return 0;
}

file_size(p) —— 文件大小(字节)

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::path p = "test.txt";
    if (fs::exists(p)) {
        uintmax_t size = fs::file_size(p);
        cout << "文件大小:" << size << "字节" << endl;
    }
    return 0;
}

last_write_time(p) —— 最后修改时间

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::path p = "test.txt";
    if (fs::exists(p)) {
        auto t = fs::last_write_time(p);
        cout << "最后修改时间已获取" << endl;
    }
    return 0;
}

目录操作(每个附完整示例)

create_directory(p) —— 创建目录

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::create_directory("mydir");
    cout << "目录已创建" << endl;
    return 0;
}

create_directories(p) —— 递归创建(含父目录)

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::create_directories("a/b/c");
    cout << "目录已递归创建" << endl;
    return 0;
}

remove(p) —— 删除文件或空目录

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::remove("test.txt");
    cout << "已删除" << endl;
    return 0;
}

remove_all(p) —— 递归删除(含目录所有内容,危险!)

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::remove_all("mydir");
    cout << "已递归删除" << endl;
    return 0;
}

rename(old, new) —— 重命名/移动

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::rename("old.txt", "new.txt");
    cout << "已重命名" << endl;
    return 0;
}

copy(src, dst) —— 复制

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::copy("src.txt", "dst.txt");
    cout << "已复制" << endl;
    return 0;
}

copy_file(src, dst) —— 复制文件

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::copy_file("src.txt", "dst.txt");
    cout << "文件已复制" << endl;
    return 0;
}

其他(每个附完整示例)

current_path() —— 当前工作目录

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    cout << fs::current_path() << endl;
    return 0;
}

temp_directory_path() —— 临时目录

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    cout << fs::temp_directory_path() << endl;
    return 0;
}

space(p) —— 磁盘空间(capacity、free、available)

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    auto s = fs::space(".");
    cout << "总容量:" << s.capacity << endl;
    cout << "空闲:" << s.free << endl;
    return 0;
}

absolute(p) —— 转绝对路径

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::path ap = fs::absolute("test.txt");
    cout << ap << endl;
    return 0;
}

canonical(p) —— 规范化路径(消除 . 和 ..)

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::path cp = fs::canonical("a/../b");
    cout << cp << endl;
    return 0;
}

遍历目录

#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    // 当前目录
    for (auto& entry : fs::directory_iterator("."))
        cout << entry.path() << endl;
    // 递归遍历子目录
    for (auto& entry : fs::recursive_directory_iterator("."))
        cout << entry.path() << endl;
    return 0;
}
#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = filesystem;
int main() {
    fs::path dir = "./data";
    if (!fs::exists(dir)) fs::create_directories(dir);
    cout << "当前目录:" << fs::current_path() << endl;
    return 0;
}
第十四章 C++20 新特性头文件

14.1 <format> —— 格式化(C++20)C++

类似 Python 的 format,比 printf 类型安全,比 iostream 简洁。

#include <format>
#include <string>
#include <iostream>
using namespace std;
int main() {
    string s = format("{} + {} = {}", 1, 2, 3);   // "1 + 2 = 3"
    string s2 = format("{:.2f}", 3.14159);         // "3.14"
    string s3 = format("{1} {0}", "world", "hello"); // "hello world"
    cout << s << endl;
    cout << s2 << endl;
    cout << s3 << endl;
    return 0;
}

14.2 <ranges> —— 范围库(C++20)C++

对 STL 算法的现代化改进,可链式调用。

#include <ranges>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1,2,3,4,5,6};
    // 过滤偶数并乘2
    auto result = v | views::filter([](int x){ return x%2==0; })
                    | views::transform([](int x){ return x*2; });
    for (int x : result) cout << x << " ";
    cout << endl;
    ranges::sort(v);  // 排序
    for (int x : v) cout << x << " ";
    cout << endl;
    return 0;
}

14.3 <span> —— 连续内存视图(C++20)C++

类似 string_view,但针对任意类型连续内存(数组、vector 等)。不拥有数据。

#include <span>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {1,2,3,4,5};
    span<int> s(v);              // 看整个vector
    span<int> sub = s.subspan(1, 3);  // 看第1到3个元素
    for (int x : sub) cout << x << " ";
    cout << endl;
    return 0;
}

14.4 <concepts> —— 概念(C++20)C++

给模板参数加约束,让模板报错更清晰。

#include <concepts>
#include <iostream>
using namespace std;
template<integral T>  // T必须是整数类型
T add(T a, T b) { return a + b; }
int main() {
    cout << add(3, 4) << endl;
    return 0;
}

常用概念:integral、floating_point、convertible_to、equality_comparable、

input_iterator、random_access_iterator、range 等。

14.5 <compare> —— 三路比较(C++20)C++

引入 <=> 运算符(太空船运算符),一次比较得出小于/等于/大于。

#include <compare>
#include <iostream>
using namespace std;
int main() {
    int a = 3, b = 5;
    auto result = a <=> b;
    if (result < 0) cout << "a < b" << endl;
    if (result == 0) cout << "a == b" << endl;
    if (result > 0) cout << "a > b" << endl;
    return 0;
}

类中可自动生成:auto operator<=>(const MyClass&) const = default;

第十六章 其他重要头文件

16.1 <cassert> —— 断言C 兼容

assert(表达式):表达式为 false 时程序崩溃并打印错误位置。

用于调试时检查"不可能发生"的情况。

定义 NDEBUG 后(Release模式)assert 失效。

#include <cassert>
#include <iostream>
using namespace std;
int main() {
    int x = 5;
    assert(x > 0);           // x应大于0
    cout << "断言通过" << endl;
    // assert(ptr != nullptr);  // 指针不应为空
    return 0;
}

C++11 静态断言(编译期):

static_assert(sizeof(int) == 4, "int必须是4字节");

16.2 <bitset> —— 位集C++

固定大小二进制位集合,适合位运算和标志位。

#include <bitset>
#include <iostream>
using namespace std;
int main() {
    bitset<8> b;             // 8位,初始全0
    b.set(3);                // 第3位设为1
    cout << b << endl;
    b.reset(3);              // 第3位设为0
    cout << b << endl;
    b.flip();                // 所有位取反
    cout << b << endl;
    cout << "第3位:" << b.test(3) << endl;  // 是否为1
    cout << "1的个数:" << b.count() << endl;
    cout << "有1:" << b.any() << endl;
    cout << "全0:" << b.none() << endl;
    cout << "全1:" << b.all() << endl;
    cout << "字符串:" << b.to_string() << endl;
    cout << "整数:" << b.to_ulong() << endl;
    return 0;
}

常用方法(每个附完整示例)

set(pos) / set() —— 指定位设1 / 全部设1

#include <bitset>
#include <iostream>
using namespace std;
int main() {
    bitset<8> b;
    b.set(3);    // 第3位=1
    cout << b << endl;
    b.set();     // 全部=1
    cout << b << endl;
    return 0;
}

reset(pos) / reset() —— 指定位设0 / 全部设0

#include <bitset>
#include <iostream>
using namespace std;
int main() {
    bitset<8> b;
    b.set();
    b.reset(3);  // 第3位=0
    cout << b << endl;
    b.reset();   // 全部=0
    cout << b << endl;
    return 0;
}

flip(pos) / flip() —— 指定位取反 / 全部取反

#include <bitset>
#include <iostream>
using namespace std;
int main() {
    bitset<8> b;
    b.flip(3);   // 第3位取反
    cout << b << endl;
    b.flip();    // 全部取反
    cout << b << endl;
    return 0;
}

test(pos) —— 指定位是否为1

#include <bitset>
#include <iostream>
using namespace std;
int main() {
    bitset<8> b;
    b.set(3);
    if (b.test(3)) cout << "第3位是1" << endl;
    return 0;
}

count() —— 有几个1

#include <bitset>
#include <iostream>
using namespace std;
int main() {
    bitset<8> b;
    b.set(3);
    b.set(5);
    size_t n = b.count();
    cout << "1的个数:" << n << endl;
    return 0;
}

any() / none() / all() —— 是否有1/全0/全1

#include <bitset>
#include <iostream>
using namespace std;
int main() {
    bitset<8> b;
    b.set(3);
    if (b.any()) cout << "有1" << endl;
    if (b.none()) cout << "全0" << endl;
    if (b.all()) cout << "全1" << endl;
    return 0;
}

to_string() / to_ulong() / to_ullong() —— 转换

#include <bitset>
#include <string>
#include <iostream>
using namespace std;
int main() {
    bitset<8> b;
    b.set(3);
    string s = b.to_string();
    unsigned long n = b.to_ulong();
    cout << "字符串:" << s << endl;
    cout << "整数:" << n << endl;
    return 0;
}

16.3 <initializer_list> —— 初始化列表(C++11)C++

支持 {a, b, c} 形式参数。自定义类支持初始化列表构造:

#include <initializer_list>
#include <vector>
#include <iostream>
using namespace std;
class MyClass {
public:
    vector<int> data;
    MyClass(initializer_list<int> list) {
        for (int x : list) data.push_back(x);
    }
};
int main() {
    MyClass obj = {1, 2, 3, 4, 5};
    for (int x : obj.data) cout << x << " ";
    cout << endl;
    return 0;
}

一般不需直接包含,用初始化列表时编译器自动处理。

16.4 <charconv> —— 低开销数值转换(C++17)C++

to_chars 和 from_chars,比 to_string/stoi 更快,不分配内存、不抛异常。

适合高性能场景。初学者用 to_string/stoi 就行。

#include <charconv>
#include <iostream>
using namespace std;
int main() {
    // 整数转字符串
    char buf[32];
    auto [ptr, ec] = to_chars(buf, buf+sizeof(buf), 42);
    *ptr = '\0';  // buf = "42"
    cout << buf << endl;

    // 字符串转整数
    int value;
    auto [ptr2, ec2] = from_chars(buf, ptr, value);
    if (ec2 == errc()) cout << value << endl;  // 42
    return 0;
}

16.5 <numbers> —— 数学常量(C++20)C++

常量(每个附完整示例)

numbers::pi —— 圆周率

#include <numbers>
#include <iostream>
using namespace std;
int main() {
    double pi = numbers::pi;  // ≈ 3.14159
    cout << "pi=" << pi << endl;
    return 0;
}

numbers::e —— 自然对数底

#include <numbers>
#include <iostream>
using namespace std;
int main() {
    double e = numbers::e;    // ≈ 2.71828
    cout << "e=" << e << endl;
    return 0;
}

numbers::sqrt2 —— 根号2

#include <numbers>
#include <iostream>
using namespace std;
int main() {
    double s = numbers::sqrt2;  // ≈ 1.41421
    cout << "sqrt2=" << s << endl;
    return 0;
}

numbers::ln2 —— ln 2

#include <numbers>
#include <iostream>
using namespace std;
int main() {
    double l = numbers::ln2;   // ≈ 0.69315
    cout << "ln2=" << l << endl;
    return 0;
}

numbers::phi —— 黄金比例

#include <numbers>
#include <iostream>
using namespace std;
int main() {
    double p = numbers::phi;   // ≈ 1.61803
    cout << "phi=" << p << endl;
    return 0;
}

16.6 <source_location> —— 源码位置(C++20)C++

获取当前代码的文件名、行号、函数名,替代 __FILE__、__LINE__ 宏。

#include <source_location>
#include <iostream>
using namespace std;
void log(source_location loc = source_location::current()) {
    cout << loc.file_name() << ":" << loc.line()
         << " " << loc.function_name() << endl;
}
int main() {
    log();
    return 0;
}
第十七章 头文件使用要点

1. 包含方式

#include <iostream> 标准库用尖括号

#include "myheader.h" 自己写的用双引号

2. 防止重复包含

方式一(推荐):#pragma once

方式二(标准):

#ifndef MYHEADER_H

#define MYHEADER_H

// 内容

#endif

3. using namespace std

- 小程序/练习可以用,省事

- 大项目/头文件中不要用,避免命名冲突

- 头文件里绝对不要写 using namespace std

4. 常用最小包含

最基础:#include <iostream>

竞赛常用(GCC):#include <bits/stdc++.h>

(包含所有标准头,编译慢,不推荐工程用)

5. C++ 版本速查

版本 主要新增特性

C++98 基础STL(vector、map、string、algorithm)

C++11 auto、lambda、智能指针、thread、unordered_map、

array、tuple、chrono、regex

C++14 make_unique、泛型lambda、变量模板

C++17 filesystem、optional、variant、string_view、

结构化绑定、if constexpr

C++20 concepts、ranges、format、coroutine、span、

<=>、numbers、source_location

C++23 expected、print、generator、mdspan、flat_map

(文档结束)