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&</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& 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.