Code Review in C++: What to Check and How to Give Feedback
\n\nCode review is one of the key stages of software development. This is especially important for C++, where memory management errors or incorrect use of the standard library can lead to serious problems. In this article, we will break down what to pay attention to when reviewing C++ code and how to give feedback that is useful, not offensive.
\n\nWhy is Code Review Important for C++?
\n\nC++ is a powerful but complex language. It gives the developer a high level of control, but requires attentiveness. Typical problems: memory leaks, undefined behavior, inefficient algorithms. A good code review helps identify such errors before they reach production.
\n\nFor beginner developers, code review is not just a check, but also a learning opportunity. By receiving feedback, you learn to write better quality code. By giving reviews, you learn to analyze and argue.
\n\nWhat to Check in C++ Code: A Checklist
\n\nTo make the review systematic, use the following checklist.
\n\n1. Memory and Resource Management
\n\nThis is the foundation of C++. Errors here are the most dangerous.
\n- \n
- Are smart pointers used instead of raw pointers?
std::unique_ptrandstd::shared_ptrshould be the standard. Raw pointers are only acceptable for observation (non-owning). \n - Are there any leaks? Check that every
newhas a correspondingdelete(if smart pointers are not used). \n - Are resources released correctly? Files, sockets, mutexes should be wrapped in RAII classes. \n
// Bad: raw pointer and manual management\nvoid process() {\n int* data = new int[100];\n // ... if an exception occurs here, there will be a leak\n delete[] data;\n}\n\n// Good: smart pointer\nvoid process() {\n auto data = std::make_unique<int[]>(100);\n // memory will be freed automatically\n}\n\n2. Type Safety and Avoiding Undefined Behavior
\n\nC++ is full of undefined behavior (UB). The reviewer must be vigilant.
\n- \n
- Is there any array out-of-bounds access? Use
std::arrayorstd::vectorwith.at()instead of raw arrays. \n - Is type casting done correctly? Avoid C-style casts. Use
static_cast,dynamic_cast,const_cast, orreinterpret_castdeliberately. \n - Are all variables initialized? Uninitialized variables are a common cause of UB. \n
- Is there any signed integer overflow? In C++, this is UB. \n
// Bad: C-style cast and uninitialized variable\nint* p = (int*)malloc(sizeof(int));\nint x; // not initialized\n*p = x; // UB\n\n// Good: explicit cast and initialization\nint* p = static_cast<int*>(std::malloc(sizeof(int)));\nint x = 0;\n*p = x;\n\n3. Performance and Efficiency
\n\nYou don't always need to chase speed, but obvious bottlenecks should be fixed.
\n- \n
- Are objects passed by value unnecessarily? Large objects should be passed by const reference (
const &). \n - Are there any unnecessary copies? Use move semantics where appropriate. \n
- Is the correct container chosen?
std::vectorfor fast index access,std::listfor frequent insertions in the middle. \n - Is a virtual function called in a hot loop? This can be slow. \n
// Slow: copying a large object\nvoid process(std::string s) { /* ... */ }\n\n// Fast: passing by const reference\nvoid process(c