C++ 代码审查:检查什么以及如何在实际中提供反馈
代码审查不仅仅是一种形式,更是提升代码质量的强大工具。在 C++ 中,由于语言的复杂性(手动内存管理、模板、多重继承),审查尤为重要。本文将分析在检查 C++ 代码时应注意什么,以及如何提出既有用又不伤人的意见。
1. 内存安全与 RAII
首先要检查的是资源管理。C++ 没有垃圾回收器,因此内存泄漏和双重释放是常见问题。关键模式是 RAII(资源获取即初始化)。
检查什么:
- 是否使用了智能指针(
std::unique_ptr、std::shared_ptr)而不是裸的new/delete? - 代码中是否有手动调用
delete?(除了少数底层工作的情况) - RAII 类是否正确实现:资源在构造函数中获取,在析构函数中释放?
- 基类中是否遗漏了虚析构函数?
// ❌ 不好:手动管理void process() { int* data = new int[100]; // ... 如果发生异常,内存会泄漏 delete[] data;}
// ✅ 好:通过 std::vector 实现 RAIIvoid process() { std::vector<int> data(100); // 异常安全}如何提供反馈: 不要说“你忘了释放内存”,而要说:“这里最好使用 std::vector 或 std::unique_ptr——它们会自动释放资源,使代码异常安全”。
2. 常量正确性与引用
C++ 允许显式指定数据不应被修改。这提高了可读性,并让编译器更好地优化代码。
检查什么:
- 所有不修改的参数是否都标记为
const? - 大对象是否通过常量引用(
const T&)传递,而不是按值传递? - 不修改对象的方法是否标记为
const? - 是否在没有绝对必要的情况下使用了
const_cast?
// ❌ 不好:复制大对象std::string toUpper(std::string s); // 复制
// ✅ 好:常量引用std::string toUpper(const std::string& s); // 无复制
// ❌ 不好:方法不是 const,尽管不改变状态class Point { int x, y;public: int getX() { return x; } // 应该是 const};
// ✅ 好int getX() const { return x; }如何提供反馈: “让我们为不修改的参数添加 const——这会使接口更清晰,并防止意外修改”。
3. STL 和算法的使用
C++ 标准库包含许多现成的解决方案。重复造轮子是新手常犯的错误。
检查什么:
- 是否有可以用算法(
std::find、std::sort、std::transform)替代的手动循环? - 容器选择是否正确?(
std::vector用于随机访问,std::list用于频繁的中间插入) - 是否使用
std::string_view来传递字符串而无需复制? - 在已知大小的情况下,是否忘记了为
std::vector调用reserve()?
// ❌ 不好:手动查找bool contains(const std::vector<int>& v, int val) { for (size_t i = 0; i < v.size(); ++i) { if (v[i] == val) return true; } return false;}
// ✅ 好:使用 STLbool contains(c