引言:为什么C++代码审查不是胆小者能做的
\n\nC++是一种赋予程序员惊人力量的语言。但正如《蜘蛛侠》中的本叔叔所说:“能力越大,责任越大”。在Python中,如果你不小心混用了int和str,可能只会得到一个异常;但在C++中,同样的疏忽可能导致未定义行为(UB),它可能会在一个月后的凌晨3点,在客户服务器上爆发。
C++代码审查不是Jira中的一个勾选框。它是你抵御段错误、内存泄漏和慢如蜗牛代码的盾牌。许多开发者(尤其是从Java或Python转来的)认为代码审查只是检查代码风格和变量命名。在C++中,情况要深入得多。你需要审视程序的灵魂:内存管理、RAII、常量正确性,以及那个智能指针是否会反过来伤到你。
\n\n在本文中,我整理了一份用于C++代码检查的实用清单。在进行下一次代码审查时,请务必使用它。我们开始吧!
\n\n1. 内存泄漏与资源管理(RAII)
\n\n这是C++的核心。如果你看到new没有对应的delete——这是一个危险信号。但在现代C++(C++11及更高版本)中,我们根本不应该手动编写new。请使用智能指针:std::unique_ptr、std::shared_ptr。如果开发者使用原始指针(int*)来拥有资源——这是一个需要质疑的理由。
糟糕代码示例(危险信号):
\n\nvoid process() {\n int* data = new int[1000];\n // ... 一些代码 ...\n if (error) {\n return; // 内存泄漏!未调用 delete\n }\n delete[] data;\n}\n\n\n良好代码示例(RAII):
\n\nvoid process() {\n std::vector<int> data(1000);\n // ... 代码 ...\n if (error) {\n return; // 没问题,vector 会自动清理内存\n }\n}\n\n\nC++代码审查中要检查什么:
\n- \n
- 代码中是否有
new/delete?如果有——为什么?为什么不用std::make_unique? \n - 是否使用
std::unique_ptr进行独占所有权? \n - 是否在只需要引用(由于原子计数器,这很昂贵)的地方按值传递了
std::shared_ptr? \n - 是否存在异常安全方面的泄漏? \n
2. 未定义行为(Undefined Behavior)
\n\n在C++中,编译器信任程序员。如果你写了无意义的代码,编译器不会责备你——它只会生成可能做任何事情的代码。UB是C++的祸害。以下是在审查中需要捕捉的内容:
\n\n- \n
- 数组越界:对于10个元素的数组使用
arr[10]。 \n - 移动后使用变量:
std::move不是魔法,移动后的对象处于有效但未定义的状态。 \n - 有符号整数溢出:
INT_MAX + 1是UB!(与Java不同,在Java中这只是简单的回绕)。 \n - 悬空引用:返回对局部变量的引用。 \n
UB示例(在代码审查中查找):
\n\nint& getValue() {\n int x = 42;\n return x; // UB!x在函数退出后被销毁\n}\n\nvoid example() {\n int& ref = getValue();\n std::cout << ref; // 可能输出42,也可能输出垃圾或崩溃\n}\n\n\n给审查者的建议:如果看到涉及int的算术运算,尤其是在循环中或处理大小时——检查是否会发生溢出。最好使用size_t作为索引,并使用std::ssize()进行安全比较。