C++ Core Guidelines

repository·master·Indexed 13 days ago

https://github.com/isocpp/cppcoreguidelines

A collaborative project led by Bjarne Stroustrup providing a set of best practices for modern C++ (C++11 and later). It focuses on high-level design, resource management, and concurrency to improve code safety, simplicity, and performance. The guidelines are designed for use with static analysis tools and are supported by the Guidelines Support Library (GSL), a lightweight, header-only library providing facilities like gsl::span.

Tokens
104.7K
Snippets
353
Records
460
Agent score
100%

What's inside C++ Core Guidelines

  1. Overview of C++ Core Guidelines

    master

    The C++ Core Guidelines are a living document designed to help developers use modern C++ (C++11 through C++20 and beyond) effectively. The guidelines focus on high-level design issues such as interfaces, resource management, memory management, and concurrency to produce code that is statically type-safe, leak-free, and performant.

    Key characteristics:

    • Focus: High-level architecture and library design rather than low-level formatting (like indentation).
    • Goal: Simplicity and safety. Rules may feel strict or counter-intuitive as they aim for long-term maintainability.
    • Tool-Oriented: Many rules are designed to be enforceable by static analysis tools. Violations in tools will reference specific guideline rules.
    • Gradual Adoption: The rules are intended to be introduced into a codebase gradually.
  2. Guidelines for Templates and Generic Programming

    master

    The C++ Core Guidelines provide a structured set of rules for using templates and generic programming effectively. These rules are categorized into several domains:

    • Template Use: High-level abstraction, algorithms, containers, and combining generic/OO techniques.
    • Concepts: Defining and using compile-time predicates to specify requirements on template arguments.
    • Template Interface: Designing how templates are presented to users (e.g., using function objects, aliases, and avoiding type-erasure).
    • Template Definition: Implementation details like minimizing dependencies, using specialization, and tag dispatch.
    • Template and Hierarchy: Rules for managing class hierarchies in the context of templates.
    • Variadic Templates: Handling functions with a variable number of arguments.
    • Metaprogramming: Using templates for compile-time computations and type emulation.
  3. Access the C++ Core Guidelines

    master

    The C++ Core Guidelines are a collection of rules designed to help developers use modern C++ (C++11 and newer) effectively. They focus on high-level issues like interfaces, resource management, memory management, and concurrency to ensure code is statically type-safe, leak-free, and performant.

    You can access the guidelines in several ways:

    • Markdown Source: The raw guidelines are maintained in CppCoreGuidelines.md using GH-flavored Markdown.
    • Web Version: A version formatted for easy browsing is available at http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines. Note that the web version is manually integrated and may be slightly behind the master branch.
    • Tooling Support: The rules are designed to be used with analysis tools that flag violations and provide links to the relevant rules.
  4. Understand the goals and principles of the C++ Core Guidelines

    master

    The C++ Core Guidelines aim to help developers adopt modern C++ (C++17 and C++20) and achieve a uniform coding style. The guidelines follow the zero-overhead principle, meaning they aim to provide abstractions that perform as well as or better than manual, lower-level implementations.

    Key Principles

    • Subset of Superset: The guidelines do not just define a restricted subset of C++. Instead, they recommend specific library components (like the Guidelines Support Library) that make error-prone features redundant, allowing those features to be effectively banned.
    • Safety Focus: Emphasis is placed on static type safety, resource safety (via RAII), range checking, and avoiding nullptr dereferences or dangling pointers.
    • Gradual Adoption: The rules are designed to be applied incrementally, making them suitable for both new projects and the modernization of existing codebases.
    • Tool-Centric: While the rules provide reasoning and examples, they are primarily intended to be used as targets for static analysis and automated tools.
  5. Guidelines for Naming and Layout (NL)

    master

    The C++ Core Guidelines provide a set of suggested naming and layout rules to promote consistency and readability. While these rules are aesthetic and often subject to debate, they serve as recommended defaults when no external style constraints (like an existing codebase or library) exist. The primary goal is consistency rather than enforcing a specific style.

    Key areas covered include:

    • Comments: Stating intent rather than repeating code, and keeping them crisp.
    • Naming: Avoiding type encoding, matching name length to scope, and using consistent styles (preferring underscore_style).
    • Layout: Maintaining consistent indentation, using K&R-derived layout, and following conventional class member declaration orders.
    • Syntax: Using ALL_CAPS for macros only, using digit separators for literals, and using conventional const notation.
  6. Guidelines for Expressions and Statements (ES)

    master

    The C++ Core Guidelines provide a comprehensive set of rules for writing expressions, statements, and declarations to ensure safety, clarity, and maintainability. These rules are categorized into:

    • General Rules: Focus on using the standard library, suitable abstractions, and avoiding redundancy (DRY).
    • Declaration Rules: Cover scope management, naming conventions (length, case, similarity), initialization (always initialize, use {} syntax), and resource management (use unique_ptr, avoid new/delete).
    • Expression Rules: Address complexity, operator precedence, pointer usage, avoiding undefined evaluation order, and safe type conversions (avoid narrowing, use nullptr).
    • Statement Rules: Recommend specific control flow structures (e.g., switch over if for multiple choices, range-based for loops) and discourage dangerous constructs like goto or do-statements.
    • Arithmetic Rules: Provide guidance on signed vs. unsigned arithmetic, bit manipulation, and preventing overflow/underflow.
  7. What is the GSL (Guidelines Support Library)?

    master

    The GSL is a small set of types and aliases specified in the guidelines to provide functionality not yet present in the C++ Standard Library.

    Key characteristics:

    • It is intended to be temporary; types will be retired once they are added to the C++ Standard.
    • The guidelines specify interfaces, not implementations. While Microsoft/GSL is a common implementation, other implementations are encouraged.
    • It is not an official ISO C++ standard component, but it is designed to serve the standard.
  8. What is gsl::dyn_array and when to use it

    master

    Concept

    gsl::dyn_array<T, Allocator> is a dynamic array designed to replace raw pointer and size idioms. It owns all its elements and provides a safer alternative to manual memory management.

    Key Characteristics:

    • Fixed Size: Unlike std::vector, it cannot grow or shrink after construction. All elements are constructed at creation.
    • Ownership: It owns its elements, making it a replacement for new T[n].
    • Safety: It does not support copy or move operations to prevent the invalidation of existing iterators or references.
    • Non-Container: It does not conform to the C++ Container Named Requirements by design to avoid unsafe usage patterns.

    Use Cases:

    • Replace new T[n] with gsl::dyn_array<T>(n).
    • Replace foo(T*, size_t) or foo(unique_ptr<T[]>&, size_t) with foo(gsl::dyn_array<T>&).
  9. What is a Profile and how to use it

    master

    A profile is a coherent, deterministic, and portably enforceable subset of the C++ Core Guidelines designed to achieve a specific safety guarantee (e.g., "absence of range errors"). Instead of applying all guidelines at once, which is often impossible in large codebases, you can adopt a profile to eliminate a specific class of errors.

    Code that is warning-free under a specific profile is considered "safe by construction" regarding the properties targeted by that profile.

    Suppressing profile checks: If you must bypass a profile check, use the [[suppress("profile_name")]] annotation on a language contract. Use this sparingly.

    [[suppress("bounds")]] char* raw_find(char* p, int n, char x)    // find x in p[0]..p[n - 1]
    {
        // ...
    }
    [[suppress("bounds")]] char* raw_find(char* p, int n, char x)
  10. What is gsl::span and why use it?

    master

    gsl::span is a non-owning view into a contiguous sequence of objects. It acts as a replacement for the error-prone (pointer, length) pattern by encapsulating both the pointer and the bounds into a single object.

    Key characteristics:

    • Non-owning: It is a view, not a container (unlike std::vector or std::array).
    • Bounds-aware: It knows its own size, reducing buffer overflow risks.
    • Deducible: It can be automatically constructed from common types like arrays or std::vector.
    // Instead of this:
    void dangerous_process_ints(const int* p, size_t n);
    
    // Use this:
    void process_ints(gsl::span<const int> s);
    
    // Usage with arrays:
    int a[100];
    process_ints(a); // Automatically deduces length 100
    
    // Usage with vectors:
    std::vector<int> v(200);
    process_ints(v); // Automatically deduces length 200
  11. Choose `for` vs `while` based on the presence of a loop variable

    master

    Select the loop type based on how the iteration is controlled:

    1. Use for when there is an obvious loop variable (e.g., an index or counter). This keeps the loop logic visible 'up front' and limits the scope of the variable.
    2. Use while when there is no obvious loop variable (e.g., an event loop waiting for a condition). Using for in these cases can be confusing if the increment/initialization parts are unrelated to the condition.

    Enforcement: Flag actions in for-initializers and for-increments that do not relate to the for-condition.

    // Use for when there is a variable
    for (gsl::index i = 0; i < vec.size(); i++) {
        // do work
    }
    
    // Use while when there is no obvious variable
    while (wait_for_event()) {
        ++events;
        // ...
    }
  12. Pass pointers and references to `const` by default (Con.3)

    master

    To prevent a called function from unexpectedly modifying an object, pass pointers and references as const whenever possible.

    • void f(char* p); implies f might modify *p.
    • void g(const char* p); guarantees g will not modify *p.

    Warning: Never "cast away const" to bypass this safety.

    void f(char* p);        // Modifies *p
    void g(const char* p);  // Does NOT modify *p