本章目标:学会"先测量再优化"、了解性能关键概念 (缓存、SSO、零开销抽象、算法复杂度)、掌握实际优化手段。 性能是 C++ 的立身之本,但**优化的第一原则是:先别优化**。
程序员最大的错觉:"我知道哪里慢"。 真实情况:90% 的猜测是错的。
正确流程:
测量工具:
auto start = std::chrono::steady_clock::now();
// ... 被测代码 ...
auto end = std::chrono::steady_clock::now();
auto us = std::chrono::duration_cast<std::chrono::microseconds>
(end - start).count();
O(1) vs O(n) vs O(n log n) vs O(n²): 数据量 10 万时,O(n²) 比 O(n log n) 慢 5000 倍。 **优化算法复杂度永远比抠指令划算**。
// 错误:在循环里反复查找
for (int i = 0; i < n; ++i)
if (std::find(v2.begin(), v2.end(), x[i]) != v2.end()) ...
// 正确:先转成哈希集合,查找变 O(1)
std::unordered_set<int> set2(v2.begin(), v2.end());
for (int x : xs)
if (set2.contains(x)) ...
常见复杂度对照:
vector 随机访问 / 尾插 O(1)
map 插入/查找 O(log n)
unordered_map 查找 O(1) 平均
sort O(n log n)
遍历容器 O(n)
手写嵌套循环里调用 O(n) 查找 O(n²) ← 最常见的性能杀手
CPU 比内存快约 100 倍,缓存(L1/L2/L3)就是为了弥合差距。 规则:**顺序访问连续内存 = 快;跳跃访问 = 慢**。
// 快:顺序遍历(缓存命中率高)
long long sum1 = 0;
for (int i = 0; i < n; ++i) sum1 += data[i];
// 慢:跳跃遍历(每步都缓存未命中)
long long sum2 = 0;
for (int i = 0; i < n; i += 1024) sum2 += data[i]; // 注意:只访问了少数
// 更典型的慢法是"按列遍历行优先矩阵",见测试
容器选择与缓存:
vector(连续内存)>> list/deque(节点分散)
游戏行业"CPU 缓存是新的内存"——flat_map 因此比 map 快
矩阵遍历顺序(row-major vs column-major):
// 二维数组按"行优先"存储
// 按行遍历(外层 i 内层 j):快
// 按列遍历(外层 j 内层 i):慢 5~20 倍
测试里有 1024x1024 矩阵对比,可以亲眼看到差异。
// 慢:字符串按值传来传去,每次拷贝
std::string slow(std::string s) { return s + "!"; }
// 快:传视图 + 返回构造到目标位置
std::string fast(std::string_view sv) {
std::string result;
result.reserve(sv.size() + 1);
result.append(sv);
result.push_back('!');
return result;
}
要点:
std::vector<int> v;
v.reserve(1'000'000); // 避免反复扩容拷贝
v.push_back(std::string("hi")) 少一次移动
std::string 自带 SSO(Small String Optimization): 短字符串(通常 ≤ 15 字节)直接存在对象内部,零堆分配! 所以:
std::string a = "hi"; // SSO:无堆分配
std::string b = a; // 拷贝也很便宜
-O0 不优化(调试用)
-O1 基本优化
-O2 常用发布优化(推荐默认)
-O3 激进优化(循环展开等,可能变大变慢)
-Os 体积优先
-march=native 用本机 CPU 指令(会失去可移植性)
-flto 链接期优化(跨文件内联,发布时开)
发布构建建议:
clang++ -std=c++26 -O2 -flto -DNDEBUG 源文件.cpp -o app
(NDEBUG 关闭 assert)
C++ 的原则:"你不用它,就不为它付费"。 例:
代价不是零——是"只为用到的功能付费"。 理解这一点:用标准库不是性能妥协,往往更快。
注意反模式:
(完整代码在测试文件里,直接跑就能看到对比数字)
练习题(配套测试:测试_第24章_性能优化.cpp)