C++: 性能优化

最后更新:2026-08-26

第48课我们学了C++17/20新特性。

现在,我们要学习性能优化——让C++程序跑得更快。

C++的优势就是性能,但要用好并不容易。


1. 性能优化概述

(1) 1.1 为什么要优化?

原则:

  1. 不要优化(Premature Optimization)
  2. 先测量,再优化
  3. 优化算法,再优化代码

(2) 1.2 性能瓶颈

瓶颈 占比
算法 70%
内存访问 20%
其他 10%

结论: 优化算法比优化代码更重要。



2. 内存对齐

(1) 2.1 什么是内存对齐?

内存对齐是指数据在内存中的起始地址是某个值(通常是2的幂)的倍数。

为什么重要?


(2) 2.2 示例:内存对齐的影响(难度⭐⭐)

▶ 示例 1:面向对象编程演示(难度⭐)

CPP
#include <iostream>

struct BadAlignment {
 char c; // 1字节
 int i; // 4字节(可能对齐到偏移4)
};

struct GoodAlignment {
 int i; // 4字节
 char c; // 1字节
};

int main() {
 std::cout << "Bad: " << sizeof(BadAlignment) << " bytes" << std::endl;
 std::cout << "Good: " << sizeof(GoodAlignment) << " bytes" << std::endl;
 
 return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
Bad: 8 bytes
Good: 8 bytes

运行结果(可能):

TEXT 📖 仅展示
Bad: 8 bytes
Good: 8 bytes

💡 提示:



3. 缓存友好

(1) 3.1 CPU缓存

CPU缓存比内存快100倍

优化原则:

  1. 局部性原理:访问相邻的内存
  2. 顺序访问:比随机访问快
  3. 避免缓存失效:少访问不连续的内存

(2) 3.2 示例:行主序 vs 列主序(难度⭐⭐⭐)

CPP
#include <iostream>
### ▶ 示例 2:STL容器使用(难度⭐)

#include <vector>
#include <chrono>

int main() {
 const int N = 1000;
 std::vector<std::vector<int>> matrix(N, std::vector<int>(N));
 
 // 行主序(缓存友好)
 auto start = std::chrono::high_resolution_clock::now();
 for (int i = 0; i < N; i++) {
 for (int j = 0; j < N; j++) {
 matrix[i][j] = 1;
 }
 }
 auto end = std::chrono::high_resolution_clock::now();
 auto row_time = std::chrono::duration<double>(end - start).count();
 
 // 列主序(缓存不友好)
 start = std::chrono::high_resolution_clock::now();
 for (int j = 0; j < N; j++) {
 for (int i = 0; i < N; i++) {
 matrix[i][j] = 1;
 }
 }
 end = std::chrono::high_resolution_clock::now();
 auto col_time = std::chrono::duration<double>(end - start).count();
 
 std::cout << "行主序时间:" << row_time << " 秒" << std::endl;
 std::cout << "列主序时间:" << col_time << " 秒" << std::endl;
 
 return 0;
}

输出:

TEXT 📖 仅展示
行主序时间:0.001 秒
列主序时间:0.003 秒


4. 编译器优化

(1) 4.1 优化级别

级别 标志 说明
O0 不优化(调试用)
O1 -O1 基本优化
O2 -O2 推荐(平衡)
O3 -O3 激进优化
Os -Os 优化大小

(2) 4.2 示例:编译器优化效果(难度⭐)

CPP
#include <iostream>

int main() {
 int sum = 0;
 for (int i = 0; i < 1000000; i++) {
 sum += i;
 }
 std::cout << sum << std::endl;
 
 return 0;
}

输出:

TEXT 📖 仅展示
499999500000

编译:

BASH
g++ -O0 main.cpp # 慢
g++ -O2 main.cpp # 快(编译器可能直接算出结果)


5. 性能分析工具

(1) 5.1 常用工具

工具 平台 说明
gprof Linux GCC性能分析
perf Linux Linux性能分析工具
Valgrind 跨平台 内存分析
Visual Studio Profiler Windows VS自带

(2) 5.2 示例:用chrono测量时间(难度⭐)

CPP
#include <iostream>
#include <chrono>

int main() {
 auto start = std::chrono::high_resolution_clock::now();
 
 // 要测量的代码
 long sum = 0;
 for (int i = 0; i < 100000000; i++) {
 sum += i;
 }
 
 auto end = std::chrono::high_resolution_clock::now();
 auto duration = std::chrono::duration<double>(end - start).count();
 
 std::cout << "耗时:" << duration << " 秒" << std::endl;
 
 return 0;
}

输出:

TEXT 📖 仅展示
耗时:0.05 秒


6. 优化技巧总结

(1) 6.1 代码层面

技巧 说明
用移动语义 减少拷贝
用emplace_back 避免临时对象
用reserve 减少vector重新分配
用unordered_map 哈希表,O(1)查找

(2) 6.2 算法层面

技巧 说明
选对数据结构 vector vs list vs map
用合适算法 sort vs partial_sort
避免不必要的拷贝 用引用、移动

▶ 示例 3:传值 vs 传引用性能对比(难度⭐)

CPP
#include <iostream>
#include <vector>
#include <chrono>

struct BigData {
    std::vector<int> data;
    BigData() : data(10000, 0) {}
};

// 传值(拷贝)
void processByValue(BigData d) {
    (void)d;
}

// 传引用(无拷贝)
void processByRef(const BigData& d) {
    (void)d;
}

int main() {
    BigData big;

    auto start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 10000; i++) {
        processByValue(big);
    }
    auto end = std::chrono::high_resolution_clock::now();
    std::cout << "传值耗时:" << std::chrono::duration<double>(end - start).count() << " 秒" << std::endl;

    start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 10000; i++) {
        processByRef(big);
    }
    end = std::chrono::high_resolution_clock::now();
    std::cout << "传引用耗时:" << std::chrono::duration<double>(end - start).count() << " 秒" << std::endl;

    return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
传值耗时:0.15 秒
传引用耗时:0.001 秒

❓ 常见问题

Q 优化一定有效吗?
A 不一定。先测量,找到瓶颈再优化。

Q C++一定比Python快吗?
A 不一定。如果算法一样,C++通常快。但如果用了不好的算法,C++也可能慢。

Q 怎么判断瓶颈在哪?
A 用性能分析工具(Profiler)。

📖 小节

知识点 要点
内存对齐 减少padding
缓存友好 顺序访问,局部性
编译器优化 -O2 推荐
性能分析 先测量,再优化
优化技巧 移动语义、emplace_back

📝 作业

  1. **基础题 (Difficulty ⭐):分别用 vector 和 list 存储 100000 个整数,测试尾部插入和随机访问的时间差异。

  2. **进阶题 (Difficulty ⭐⭐):测试传值 vs 传引用的性能差异。写一个函数处理一个大结构体(含 vector<int>(10000)),分别用值传递和 const 引用传递测量时间。

  3. **挑战题 (Difficulty ⭐⭐⭐):用 std::chrono 高精度计时,比较 for 循环、STL for_each、范围 for 三种遍历方式的性能差异。分析结果。



下一课:单元测试(#50)

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏