Clean Code in C++: Principles and Practical Examples
Every C++ developer sooner or later faces the problem of maintaining their own or someone else's code. Complex templates, overloaded functions, and endless macros turn a project into a nightmare. The concept of Clean Code, popularized by Robert Martin, offers simple yet effective rules that make code understandable, safe, and easy to modify. In this article, we will break down the key principles of Clean Code as applied to C++ and show how to apply them in practice.
1. Variable and Function Names: Say What You Do
The first rule of clean code is that a name should reveal the developer's intent. In C++, this is especially important due to the abundance of pointers, references, and overloads.
Bad example:
int d; // elapsed time in daysvoid f(int* a, int n); // ???Good example:
int daysSinceLastLogin;void processUserData(const std::vector<int>& userIds);Use full words, avoid single-letter variables (except for indices in short loops). For boolean variables, use prefixes is, has, should:
bool isValidInput;bool hasPermissions;Name classes and structures with nouns, and functions with verbs or verb phrases: class UserAccount, void calculateSalary().
2. Functions: Small, with a Single Responsibility
A function should do only one thing and do it well. The maximum length is 20-30 lines. If a function is longer, break it down into helper functions.
Bad example (monolithic function):
void processOrder(Order& order) { // payment validation // inventory update // send email // logging // receipt generation}Good example (decomposition):
void processOrder(Order& order) { if (!validatePayment(order)) return; updateInventory(order); sendConfirmationEmail(order); logTransaction(order); generateReceipt(order);}Avoid side effects. A function should not modify global variables or arguments passed by reference without explicitly indicating this in the name (resetData, fillBuffer).
3. Memory and Resource Management: RAII and Smart Pointers
C++ gives full control over memory, but this leads to leaks. Clean Code suggests using the RAII (Resource Acquisition Is Initialization) idiom and smart pointers instead of raw new/delete.
Bad example (manual management):
void process() { int* data = new int[100]; // ... lots of code ... if (error) { delete[] data; return; } delete[] data;}Good example (RAII):
void process() { std::unique_ptr<int[]> data = std::make_unique<int[]>(100); // ... code ... // delete is called automatically when leaving scope}For shared ownership, use std::shared_ptr; for weak references, use std::weak_ptr. Never return raw pointers to internal data — use references or smart pointers.
4. Error Handling: Exceptions and Return Codes
Clean code requires explicit and predictable error handling. In C++, there are two main approaches: exceptions and return codes. Choose one style within a project.
Bad example (ignoring errors):
int divide(int a, int b) { return a / b; // division by zero!}Good example (exceptions):
int divide(i