C++ Code Review | 'Checklist' 20 Items [Production Essential]
이 글의 핵심
C++ Code Review - "Checklist" 20 Items [Production Essential]. Explains memory safety (5), performance (5), and readability (5) for C++ code review with practical code examples.
Memory Safety (5)
1. Check Memory Leaks
Below is an implementation example using C++. Understand the role of each part while examining the code.
// ❌ Leak
void bad() {
int* ptr = new int[100];
// No delete[]!
}
// ✅ RAII
void good() {
vector<int> v(100); // Automatic deallocation
}
2. Dangling Pointers
Below is an implementation example using C++. Understand the role of each part while examining the code.
// ❌ Dangerous
int* bad() {
int x = 10;
return &x; // Returning local variable address!
}
// ✅ Safe
int good() {
int x = 10;
return x; // Return value
}
3. double delete
Below is an implementation example using C++. Understand the role of each part while examining the code.
// ❌ Crash
int* ptr = new int(10);
delete ptr;
delete ptr; // double delete!
// ✅ Set nullptr
int* ptr = new int(10);
delete ptr;
ptr = nullptr;
delete ptr; // Safe
4. Array Out of Bounds
Below is an implementation example using C++. Perform branching with conditionals. Understand the role of each part while examining the code.
// ❌ Dangerous
int arr[10];
arr[10] = 5; // Out of bounds!
// ✅ Check
if (index < 10) {
arr[index] = 5;
}
// ✅ Use vector
vector<int> v(10);
v.at(10) = 5; // Throws exception
5. Use Smart Pointers
Below is an implementation example using C++. Try running the code directly to check its operation.
// ❌ raw pointer
int* ptr = new int(10);
// ....complex logic ...
delete ptr; // Easy to forget
// ✅ Smart pointer
auto ptr = make_unique<int>(10);
// Automatic deallocation
Understanding with everyday analogy: Think of memory as an apartment building. Stack is like an elevator - fast but limited space. Heap is like a warehouse - spacious but takes time to find things. Pointers are like notes pointing to addresses like “Floor 3, Room 302”.
Performance (5)
6. Unnecessary Copying
Below is an implementation example using C++. Try running the code directly to check its operation.
// ❌ Copy
void process(vector<int> data) { // Copy!
// ...
}
// ✅ Reference
void process(const vector<int>& data) {
// ...
}
7. Use reserve
Below is an implementation example using C++. Process data with loops. Understand the role of each part while examining the code.
// ❌ Multiple reallocations
vector<int> v;
for (int i = 0; i < 1000; i++) {
v.push_back(i);
}
// ✅ Pre-allocate
vector<int> v;
v.reserve(1000);
for (int i = 0; i < 1000; i++) {
v.push_back(i);
}
8. Appropriate Data Structure
Below is an implementation example using C++. Understand the role of each part while examining the code.
// ❌ Slow (O(n) search)
vector<int> v;
find(v.begin(), v.end(), x);
// ✅ Fast (O(log n) or O(1))
set<int> s;
s.find(x);
unordered_set<int> us;
us.find(x);
9. String Concatenation
Below is an implementation example using C++. Process data with loops. Understand the role of each part while examining the code.
// ❌ Slow
string result;
for (const auto& s : strings) {
result += s; // Reallocation each time
}
// ✅ Fast
ostringstream oss;
for (const auto& s : strings) {
oss << s;
}
string result = oss.str();
10. move Semantics
Below is an implementation example using C++. Try running the code directly to check its operation.
// ❌ Copy
vector<int> v1 = getData();
vector<int> v2 = v1; // Copy
// ✅ move
vector<int> v1 = getData();
vector<int> v2 = move(v1); // move
Readability (5)
11. Clear Variable Names
Below is an implementation example using C++. Try running the code directly to check its operation.
// ❌ Unclear
int d; // What does it mean?
int tmp;
// ✅ Clear
int daysUntilExpiry;
int userCount;
12. Function Length
Here is detailed implementation code using C++. Understand the role of each part while examining the code.
// ❌ Too long function (100+ lines)
void processData() {
// ....100 lines ...
}
// ✅ Split into small functions
void validateData() { /* ....*/ }
void transformData() { /* ....*/ }
void saveData() { /* ....*/ }
void processData() {
validateData();
transformData();
saveData();
}
13. Remove Magic Numbers
Here is detailed implementation code using C++. Perform branching with conditionals. Understand the role of each part while examining the code.
// ❌ Magic number
if (status == 2) { // What is 2?
// ...
}
// ✅ Constant
const int STATUS_ACTIVE = 2;
if (status == STATUS_ACTIVE) {
// ...
}
// ✅ enum
enum class Status { Inactive, Pending, Active };
if (status == Status::Active) {
// ...
}
14. Comments
Below is an implementation example using C++. Try running the code directly to check its operation.
// ❌ Unnecessary comment
int x = 10; // Assign 10 to x
// ❌ Outdated comment
// TODO: Fix later (2020)
// ✅ Explain intent
// Set timeout to 10 seconds (considering server response time)
int timeout = 10;
15. const Correctness
Below is an implementation example using C++. Process data with loops. Understand the role of each part while examining the code.
// ❌ No const
void print(vector<int>& v) {
for (int x : v) {
cout << x << " ";
}
}
// ✅ Add const
void print(const vector<int>& v) {
for (int x : v) {
cout << x << " ";
}
}
Safety (5)
16. Exception Safety
Below is an implementation example using C++. Understand the role of each part while examining the code.
// ❌ Leak on exception
void bad() {
int* ptr = new int[100];
riskyOperation(); // May throw exception
delete[] ptr; // Not executed!
}
// ✅ RAII
void good() {
vector<int> v(100);
riskyOperation(); // Safe even if exception thrown
}
17. nullptr Check
Below is an implementation example using C++. Ensure stability through error handling and perform branching with conditionals. Understand the role of each part while examining the code.
// ❌ No check
void process(int* ptr) {
*ptr = 10; // What if ptr is nullptr?
}
// ✅ Check
void process(int* ptr) {
if (!ptr) {
throw invalid_argument("ptr is null");
}
*ptr = 10;
}
18. Integer Overflow
Below is an implementation example using C++. Ensure stability through error handling, perform branching with conditionals, and try running the code directly to check its operation.
// ❌ Overflow possible
int a = INT_MAX;
int b = a + 1; // Overflow!
// ✅ Check
if (a > INT_MAX - 1) {
throw overflow_error("overflow");
}
int b = a + 1;
19. Input Validation
Below is an implementation example using C++. Ensure stability through error handling and perform branching with conditionals. Understand the role of each part while examining the code.
// ❌ No validation
void setAge(int age) {
this->age = age; // Negative possible?
}
// ✅ Validation
void setAge(int age) {
if (age < 0 || age > 150) {
throw invalid_argument("invalid age");
}
this->age = age;
}
20. Thread Safety
Here is detailed implementation code using C++. Understand the role of each part while examining the code.
// ❌ Race condition
int counter = 0;
void increment() {
counter++; // Not thread-safe!
}
// ✅ mutex
mutex mtx;
int counter = 0;
void increment() {
lock_guard<mutex> lock(mtx);
counter++;
}
Code Review Process
1. Automatic Checks
Below is an implementation example using bash. Ensure stability through error handling and try running the code directly to check its operation.
# Compilation warnings
g++ -Wall -Wextra -Werror
# Static analysis
cppcheck --enable=all .
clang-tidy *.cpp
# Format check
clang-format -i *.cpp
2. Manual Checks
Below is an implementation example using code. Try running the code directly to check its operation.
□ Does code meet requirements?
□ Are tests sufficient?
□ Is error handling appropriate?
□ Are there performance issues?
□ Are there security vulnerabilities?
□ Is readability good?
□ Is it documented?
3. Writing Feedback
Below is an implementation example using code. Try running the code directly to check its operation.
✅ Good feedback:
"line 42: Receiving vector as const reference can avoid copying."
❌ Bad feedback:
"This code is a mess."
Practical Examples
Example 1: Code Before Review
Below is an implementation example using C++. Process data with loops. Understand the role of each part while examining the code.
void process(vector<int> data) {
int* arr = new int[data.size()];
for (int i = 0; i <= data.size(); i++) {
arr[i] = data[i] * 2;
}
// ....processing ...
delete arr; // Not delete[]!
}
Issues:
- Unnecessary copy (vector)
- Using raw pointer
- Out of bounds (i <= size)
- delete vs delete[]
Example 2: Code After Review
Below is an implementation example using C++. Process data with loops. Understand the role of each part while examining the code.
void process(const vector<int>& data) {
vector<int> result;
result.reserve(data.size());
for (int value : data) {
result.push_back(value * 2);
}
// ....processing ...
}
Improvements:
- Removed copy with const reference
- Using vector (RAII)
- Range-based for
- Performance improvement with reserve
FAQ
Q1: How often should code review be done?
A: Ideally review every PR/commit.
Q2: How many reviewers?
A: Minimum 1, recommend 2 or more for important code.
Q3: Review time?
A: About 1 hour per 200-400 lines is appropriate.
Q4: Automation tools?
A:
- clang-tidy
- cppcheck
- SonarQube
- Coverity
Q5: Code review culture?
A:
- Constructive feedback
- Suggest improvements, don’t attack code
- Use as learning opportunity
Q6: How to create review checklist?
A:
- Analyze team’s past bugs
- Organize frequently occurring mistakes
- Include coding style guide
Related Reading (Internal Links)
Other articles connected to this topic.
- C++ RAII Pattern | “Resource Management” Complete Guide
- C++ const Complete Guide | “const Correctness” Practical Usage
- C++ Smart Pointers | unique_ptr/shared_ptr “Memory Safety” Guide
Related Articles
- C++ const Complete Guide |
- C++ Static Analysis Tools | Clang-Tidy·Cppcheck·SonarQube [#53-5]
- Arrays and Lists | Essential Data Structures for Coding Tests Complete Summary
- C++ Adapter Pattern Complete Guide | Interface Conversion and Compatibility
- C++ ADL |