Summary of High-Quality C++ Programming Guidelines

The core goal of high-quality C++ programming is to write maintainable, scalable, efficient, and safe code. Below are practical high-quality programming guidelines covering key dimensions such as coding standards, design principles, performance optimization, and security practices:

1. Coding Standards and Style

1. Naming Conventions

  • Variables/Functions: Use <span>snake_case</span> (e.g., <span>user_name</span>, <span>calculate_sum</span>), avoid abbreviations (unless they are widely known abbreviations like <span>id</span>, <span>url</span>).
  • Classes/Structures: Use <span>PascalCase</span> (e.g., <span>UserInfo</span>, <span>FileHandler</span>), reflecting the concept of “things”.
  • Constants: Use <span>UPPER_SNAKE_CASE</span> (e.g., <span>MAX_BUFFER_SIZE</span>), to indicate their immutability.
  • Naming should be “self-explanatory”, avoiding vague names like <span>temp</span>, <span>data</span> (for example, use <span>remaining_bytes</span> instead of <span>left</span>).

2. Code Formatting

  • Indentation: Use 4 spaces consistently (avoid tabs <span> </span>, to prevent inconsistent display across platforms).
  • Braces: The left brace for function/class definitions should be on a new line, while the left brace for conditional/loop statements should follow the statement (e.g., <span>if (x) {</span>).
  • Blank Lines: Insert blank lines between logical blocks (functions, loops, conditions) to distinguish code levels.
  • Line Length: Keep within 80-120 characters; long lines should be split (preferably after operators).

3. Commenting Standards

  • Classes/Functions: Use Doxygen-style comments to describe functionality, parameters, return values, and exceptions (e.g., <span>//</span><summary><span>Calculate the sum of two numbers</span></summary>).
  • Complex Logic: Comment “why” before code blocks (rather than “what”), such as the key ideas of an algorithm.
  • Avoid Redundant Comments: Comments like <span>i++ // Increment i</span> reduce readability.

2. Types and Memory Management

1. Prefer Modern C++ Types

  • Use <span>bool</span> for logical values, avoid using <span>int</span> instead; use <span>size_t</span> for lengths/indices (instead of <span>int</span>, to prevent negative issues).
  • Use <span>std::string</span> instead of <span>char*</span>, and use STL containers like <span>std::vector</span>/<span>std::map</span> to avoid manual array management.
  • Use <span>enum class</span> (strongly typed enumeration) to avoid implicit conversions:<span>enum class Color { Red, Green };</span>.

2. Memory Safety

  • Prohibit raw pointers: Prefer using smart pointers <span>std::unique_ptr</span> (exclusive ownership), <span>std::shared_ptr</span> (shared ownership) to avoid memory leaks and dangling pointers.
  • Avoid <span>new/delete</span>: Use containers and smart pointers for memory management; when manual management is necessary, ensure <span>new</span> and <span>delete</span> are paired (use <span>delete[]</span> for arrays).
  • Be cautious of wild pointers: Initialize pointers to <span>nullptr</span> (instead of <span>NULL</span>), to avoid dereferencing uninitialized pointers.

3. Function and Interface Design

1. Function Design Principles

  • Single Responsibility: A function should do one thing only, with a length of 20-30 lines; if too long, it should be split.
  • Parameters and Return Values:
    • Input parameters should use `const&` (e.g., `const std::string& name`), to avoid unnecessary copies.
    • Output parameters should preferably be passed via return values (e.g., `return std::pair()`), rather than pointers/references (unless necessary).
    • Avoid too many parameters (recommended not to exceed 4); if too many, encapsulate them in a structure.
  • Avoid Side Effects: Functions should be as stateless as possible (input determines output), reducing modifications to global variables or external states.

2. Interface Abstraction

  • Define interfaces using pure virtual functions (<span>class Interface { virtual void func() = 0; };</span>), depending on abstraction rather than concrete implementations (Dependency Inversion Principle).
  • Interfaces should be stable: Once published, avoid modifying existing method signatures; extensions can be made by adding new interfaces.

4. Object-Oriented Design and Design Patterns

1. Class Design

  • Encapsulation: Member variables should be set to <span>private</span>, accessed through <span>public</span> methods (<span>getter/setter</span>), hiding internal implementations.
  • Inheritance: Prefer composition (<span>has-a</span>) over inheritance (<span>is-a</span>); when inheriting, ensure compliance with the “Liskov Substitution Principle” (subclasses can replace parent classes without changing behavior).
  • Destructors: Base class destructors must be virtual (<span>virtual ~Base() = default;</span>), to avoid memory leaks when deleting subclass objects.

2. Design Patterns

  • Use patterns appropriately based on the scenario: for example, use <span>Factory Pattern</span> to encapsulate object creation, <span>Observer Pattern</span> for event notification, and <span>Singleton Pattern</span> to manage globally unique resources (with attention to thread safety).
  • Avoid Over-Design: Do not use patterns just for the sake of using patterns; simple problems should have simple solutions.

5. Performance Optimization

1. Reduce Unnecessary Copies

  • Use <span>const&amp;</span> to pass large objects, and use move semantics (<span>std::move</span>) to transfer resource ownership (e.g., <span>std::vector</span><span>func() { …; return std::move(result); }</span>).
  • Preallocate container space:<span>std::vector</span> calls <span>reserve(n)</span> to avoid performance loss from dynamic resizing.

2. Efficient Use of STL

  • Prefer range-based for loops for iteration (<span>for (const auto&amp; x : vec) { … }</span>), to avoid out-of-bounds risks.
  • Algorithm Selection: Use <span>std::find_if</span> instead of handwritten loops, and <span>std::sort</span> is more efficient than custom sorting (STL implementations are optimized).

3. Avoid Premature Optimization

  • First ensure code correctness and readability, then optimize after identifying performance bottlenecks using profiling tools (e.g., gprof, perf).
  • Focus on optimizing hot code: loops and frequently called functions should be prioritized, such as reducing memory allocations within loops and merging duplicate calculations.

6. Error Handling and Security

1. Exception Handling

  • Use exceptions (<span>throw</span>) for rare errors (e.g., file not found), not for expected situations (e.g., user input errors).
  • Exception Specifications: Clearly specify exceptions that functions may throw (recommended to use <span>noexcept</span> to mark functions that do not throw exceptions after C++17), avoid raw <span>catch(…)</span> (logging is necessary).
  • RAII Principle: Use object lifetimes to manage resources (e.g., <span>std::lock_guard</span> to manage locks), ensuring resources are correctly released when exceptions occur.

2. Input Validation

  • Validate all external inputs (user input, network data) to avoid out-of-bounds access, format errors, etc. (e.g., check if <span>std::vector</span> indices are within valid ranges).

3. Thread Safety

  • Shared data must be locked (<span>std::mutex</span>), or use atomic types (<span>std::atomic</span>).
  • Avoid deadlocks: Lock in a fixed order, use <span>std::lock</span> to lock multiple locks simultaneously, or set timeouts (<span>std::timed_mutex</span>).

7. Tools and Practices

1. Static Analysis

  • Use <span>clang-tidy</span> and <span>cppcheck</span> to detect potential issues (e.g., uninitialized variables, memory leaks).
  • Enable compiler warnings and treat warnings as errors.

2. Testing

  • Unit Testing: Cover key functions and validate boundary conditions (e.g., empty input, maximum values).
  • Code Coverage: Ensure core logic is covered by tests.

3. Version Control and Collaboration

  • Self-review code before submission to ensure compliance with team standards; use <span>git</span> for version management, and commit messages should be clear (e.g., <span>fix: Fix memory leak during user login</span>).

Conclusion

The core of high-quality C++ code is “human-centered”— enabling others who read the code to quickly understand the logic while also considering machine execution efficiency.

Leave a Comment