Skip to main content
C++, despite its power and flexibility, has several common anti-patterns that can lead to bugs, performance issues, and maintenance problems. Here are the most important anti-patterns to avoid when writing C++ code.
Raw pointers don’t express ownership, leading to memory leaks or double-free errors. Use smart pointers (std::unique_ptr, std::shared_ptr) to clearly express ownership semantics.
Manual resource management is error-prone. Use RAII (Resource Acquisition Is Initialization) to automatically manage resources through object lifetimes.
Use const for methods that don’t modify object state, parameters that shouldn’t be modified, and return values that shouldn’t be modified.
Standard algorithms are more expressive, less error-prone, and often more efficient than raw loops. Use them whenever possible.
Write clear, maintainable code first, then optimize only after profiling identifies bottlenecks.
Use modern C++ features like std::string, std::string_view, std::optional, std::variant, and others to write safer, more expressive code.
Use nullptr instead of NULL or 0 for null pointers. It’s type-safe and avoids ambiguity with integer literals.
Use auto for complex types to improve readability and maintainability, especially for iterators and lambda types.
Use range-based for loops for cleaner, more readable iteration over containers.
Use structured bindings (C++17) to unpack tuples, pairs, and other structured data more cleanly.
Use std::optional (C++17) to represent values that may or may not be present, instead of using special values or output parameters.
Use std::variant (C++17) for type-safe unions, and std::visit with overloaded lambdas for processing.
Use move semantics to avoid unnecessary copying of large objects, especially when transferring ownership.
Use std::string_view (C++17) for functions that only need to read string data, to avoid unnecessary copies.
Use proper exception handling to deal with errors, and consider using the “Resource Acquisition Is Initialization” (RAII) pattern to ensure resources are properly cleaned up.
Use containers and smart pointers instead of manual memory management to avoid memory leaks and other memory-related bugs.
Follow the Rule of Zero (use standard containers and smart pointers), or the Rule of Five (define all special member functions) to properly manage resources.
Use forward declarations instead of including headers when you only need to refer to a class by pointer or reference, to reduce compilation dependencies and build times.
Always initialize variables to avoid undefined behavior. Use uniform initialization (curly braces) when appropriate.
Use exceptions for exceptional conditions, and consider using std::expected (C++23) or similar for expected failures.