Communitygithub.com

C++ 编码规范 (C++ Core Guidelines)

基于 C++ Core Guidelines (isocpp.github.io) 的 C++ 编码规范。在编写、审查或重构 C++ 代码时使用,以强制执行现代、安全且惯用的实践。

C++ 编码规范 (C++ Core Guidelines) 是什么?

这份技能文档提供了基于 C++ Core Guidelines 的全面现代 C++ (C++17/20/23) 编码规范。它旨在帮助开发者编写更安全、更清晰、更易于维护的 C++ 代码,通过强调类型安全、资源安全、不变性和代码清晰度。该规范适用于编写新的 C++ 代码、审查或重构现有代码、在 C++ 项目中做出架构决策以及强制执行一致的代码风格。它明确排除了非 C++ 项目、无法采用现代 C++ 特性的遗留 C 代码库以及特定硬件约束可能与指导原则冲突的嵌入式/裸机环境。文档内容涵盖了核心原则(如 RAII、默认不可变性、值语义)、详细规则,并针对哲学与接口、函数、类与类层次结构、资源管理、表达式与语句、错误处理、常量与不可变性以及并发与并行等关键领域提供了具体的“应该做”和“不应该做”的示例,使其成为团队和 AI 编码助手执行高质量 C++ 实践的理想参考。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/cpp-coding-standards

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

C++ 编码规范 (C++ Core Guidelines) 是做什么的?

基于 C++ Core Guidelines 的现代 C++ (C++17/20/23) 全面编码规范。强制执行类型安全、资源安全、不变性和代码清晰度。

使用时机

  • 编写新的 C++ 代码(类、函数、模板)
  • 审查或重构现有的 C++ 代码
  • 在 C++ 项目中进行架构决策
  • 在 C++ 代码库中强制执行一致的代码风格
  • 在语言特性之间进行选择(例如,enum vs enum class,原始指针 vs 智能指针)

不应使用的情况

  • 非 C++ 项目
  • 无法采用现代 C++ 特性的遗留 C 代码库
  • 特定指导原则与硬件约束冲突的嵌入式/裸机环境(需选择性适配)

贯穿全局的原则

以下主题贯穿整个指导原则,并构成了其基础:

  1. 到处使用 RAII (P.8, R.1, E.6, CP.20): 将资源生命周期绑定到对象生命周期
  2. 默认不可变 (P.10, Con.1-5, ES.25): 从 const/constexpr 开始;可变性是例外
  3. 类型安全 (P.4, I.4, ES.46-49, Enum.3): 利用类型系统在编译时防止错误
  4. 表达意图 (P.3, F.1, NL.1-2, T.10): 名称、类型和概念应传达目的
  5. 最小化复杂性 (F.2-3, ES.5, Per.4-5): 简单的代码是正确的代码
  6. 值语义优先于指针语义 (C.10, R.3-5, F.20, CP.31): 优先按值返回和使用作用域对象

哲学与接口 (P., I.)

关键规则

规则概要
P.1直接用代码表达思想
P.3表达意图
P.4理想情况下,程序应该是静态类型安全的
P.5编译时检查优先于运行时检查
P.8不要泄漏任何资源
P.10不可变数据优先于可变数据
I.1使接口显式
I.2避免非 const 的全局变量
I.4使接口精确定义且强类型化
I.11永远不要通过原始指针或引用传递所有权
I.23保持函数参数数量较少

应该做

// P.10 + I.4: 不可变、强类型接口
struct Temperature {
    double kelvin;
};

Temperature boil(const Temperature& water);

不应该做

// 弱接口:所有权不明确,单位不明确
double boil(double* temp);

// 非 const 全局变量
int g_counter = 0;  // I.2 违反

函数 (F.*)

关键规则

规则概要
F.1将有意义的操作封装为精心命名的函数
F.2一个函数应执行单一逻辑操作
F.3保持函数短小简洁
F.4如果函数可能在编译时求值,则声明为 constexpr
F.6如果函数必须不抛出异常,则声明为 noexcept
F.8优先使用纯函数
F.16对于“输入”参数,廉价可复制类型按值传递,其他类型通过 const& 传递
F.20对于“输出”值,优先使用返回值而非输出参数
F.21要返回多个“输出”值,优先返回一个结构体
F.43永远不要返回指向局部对象的指针或引用

参数传递

// F.16: 廉价类型按值传递,其他类型通过 const& 传递
void print(int x);                           // 廉价: 按值传递
void analyze(const std::string& data);       // 昂贵: 通过 const& 传递
void transform(std::string s);               // 接收参数: 按值传递 (将移动)

// F.20 + F.21: 返回值,而非输出参数
struct ParseResult {
    std::string token;
    int position;
};

ParseResult parse(std::string_view input);   // 好: 返回结构体

// 不好: 输出参数
void parse(std::string_view input,
           std::string& token, int& pos);    // 避免这样做

纯函数和 constexpr

// F.4 + F.8: 尽可能使用纯函数、constexpr
constexpr int factorial(int n) noexcept {
    return (n <= 1) ? 1 : n * factorial(n - 1);
}

static_assert(factorial(5) == 120);

反模式

  • 从函数返回 T&& (F.45)
  • 使用 va_arg / C 风格可变参数 (F.55)
  • 在传递给其他线程的 lambda 中通过引用捕获 (F.53)
  • 返回 const T 会抑制移动语义 (F.49)

类与类层次结构 (C.*)

关键规则

规则概要
C.2如果存在不变量,使用 class;如果数据成员独立变化,使用 struct
C.9最小化成员的暴露
C.20如果可以不定义默认操作,就不要定义(零原则)
C.21如果你定义或 =delete 了任何拷贝/移动/析构函数,则需处理所有(五原则)
C.35基类析构函数:公有虚析构或受保护的非虚析构
C.41构造函数应创建一个完全初始化的对象
C.46声明单参数构造函数为 explicit
C.67多态类应禁止公有拷贝/移动
C.128虚函数:精确指定 virtual、override 或 final 中的一个

零原则

// C.20: 让编译器生成特殊成员函数
struct Employee {
    std::string name;
    std::string department;
    int id;
    // 不需要显式定义析构函数、拷贝/移动构造函数或赋值运算符
};

五原则

// C.21: 如果你必须管理资源,定义所有五个
class Buffer {
public:
    explicit Buffer(std::size_t size)
        : data_(std::make_unique<char[]>(size)), size_(size) {}

    ~Buffer() = default;

    Buffer(const Buffer& other)
        : data_(std::make_unique<char[]>(other.size_)), size_(other.size_) {
        std::copy_n(other.data_.get(), size_, data_.get());
    }

    Buffer& operator=(const Buffer& other) {
        if (this != &other) {
            auto new_data = std::make_unique<char[]>(other.size_);
            std::copy_n(other.data_.get(), other.size_, new_data.get());
            data_ = std::move(new_data);
            size_ = other.size_;
        }
        return *this;
    }

    Buffer(Buffer&&) noexcept = default;
    Buffer& operator=(Buffer&&) noexcept = default;

private:
    std::unique_ptr<char[]> data_;
    std::size_t size_;
};

类层次结构

// C.35 + C.128: 虚析构函数,使用 override
class Shape {
public:
    virtual ~Shape() = default;
    virtual double area() const = 0;  // C.121: 纯接口
};

class Circle : public Shape {
public:
    explicit Circle(double r) : radius_(r) {}
    double area() const override { return 3.14159 * radius_ * radius_; }

private:
    double radius_;
};

反模式

  • 在构造函数/析构函数中调用虚函数 (C.82)
  • 对非平凡类型使用 memset/memcpy (C.90)
  • 为虚函数及其覆盖者提供不同的默认参数 (C.140)
  • 将数据成员设为 const 或引用,这会抑制移动/拷贝 (C.12)

资源管理 (R.*)

关键规则

规则概要
R.1使用 RAII 自动管理资源
R.3原始指针 (T*) 是非拥有的
R.5优先使用作用域对象;不要不必要地在堆上分配
R.10避免使用 malloc()/free()
R.11避免显式调用 new 和 delete
R.20使用 unique_ptr 或 shared_ptr 来表示所有权
R.21除非需要共享所有权,否则优先使用 unique_ptr 而不是 shared_ptr
R.22使用 make_shared() 来创建 shared_ptr

智能指针用法

// R.11 + R.20 + R.21: 使用 RAII 和智能指针
auto widget = std::make_unique<Widget>("config");  // 唯一所有权
auto cache  = std::make_shared<Cache>(1024);        // 共享所有权

// R.3: 原始指针 = 非拥有观察者
void render(const Widget* w) {  // 不拥有 w
    if (w) w->draw();
}

render(widget.get());

RAII 模式

// R.1: 资源获取即初始化
class FileHandle {
public:
    explicit FileHandle(const std::string& path)
        : handle_(std::fopen(path.c_str(), "r")) {
        if (!handle_) throw std::runtime_error("无法打开: " + path);
    }

    ~FileHandle() {
        if (handle_) std::fclose(handle_);
    }

    FileHandle(const FileHandle&) = delete;
    FileHandle& operator=(const FileHandle&) = delete;
    FileHandle(FileHandle&& other) noexcept
        : handle_(std::exchange(other.handle_, nullptr)) {}
    FileHandle& operator=(FileHandle&& other) noexcept {
        if (this != &other) {
            if (handle_) std::fclose(handle_);
            handle_ = std::exchange(other.handle_, nullptr);
        }
        return *this;
    }

private:
    std::FILE* handle_;
};

反模式

  • 裸 new/delete (R.11)
  • 在 C++ 代码中使用 malloc()/free() (R.10)
  • 在单个表达式中进行多次资源分配 (R.13 -- 异常安全风险)
  • 使用 shared_ptr 而 unique_ptr 就足够的情况 (R.21)

表达式与语句 (ES.*)

关键规则

规则概要
ES.5保持作用域较小
ES.20始终初始化对象
ES.23优先使用 {} 初始化语法
ES.25除非打算修改,否则将对象声明为 const 或 constexpr
ES.28使用 lambda 进行复杂 const 变量的初始化
ES.45避免魔数;使用符号常量
ES.46避免窄化/有损算术转换
ES.47使用 nullptr 而不是 0 或 NULL
ES.48避免类型转换
ES.50不要去掉 const

初始化

// ES.20 + ES.23 + ES.25: 始终初始化,优先使用 {},默认为 const
const int max_retries{3};
const std::string name{"widget"};
const std::vector<int> primes{2, 3, 5, 7, 11};

// ES.28: 用于复杂 const 初始化的 lambda
const auto config = [&] {
    Config c;
    c.timeout = std::chrono::seconds{30};
    c.retries = max_retries;
    c.verbose = debug_mode;
    return c;
}();

反模式

  • 未初始化的变量 (ES.20)
  • 使用 0 或 NULL 作为指针 (ES.47 -- 使用 nullptr)
  • C 风格类型转换 (ES.48 -- 使用 static_cast, const_cast 等)
  • 去掉 const (ES.50)
  • 没有命名常量的魔数 (ES.45)
  • 混合有符号和无符号算术运算 (ES.100)
  • 在嵌套作用域中重用名称 (ES.12)

错误处理 (E.*)

关键规则

规则概要
E.1在设计初期制定错误处理策略
E.2抛出异常以表示函数无法执行其指定的任务
E.6使用 RAII 防止资源泄漏
E.12当抛出异常不可能或不可接受时,使用 noexcept
E.14使用专门设计的用户定义类型作为异常
E.15按值抛出,按引用捕获
E.16析构函数、释放操作和 swap 绝对不能失败
E.17不要试图在每个函数中捕获所有异常

异常层次结构

// E.14 + E.15: 自定义异常类型,按值抛出,按引用捕获
class AppError : public std::runtime_error {
public:
    using std::runtime_error::runtime_error;
};

class NetworkError : public AppError {
public:
    NetworkError(const std::string& msg, int code)
        : AppError(msg), status_code(code) {}
    int status_code;
};

void fetch_data(const std::string& url) {
    // E.2: 抛出异常以表示失败
    throw NetworkError("连接被拒绝", 503);
}

void run() {
    try {
        fetch_data("https://api.example.com");
    } catch (const NetworkError& e) {
        log_error(e.what(), e.status_code);
    } catch (const AppError& e) {
        log_error(e.what());
    }
    // E.17: 不要在这里捕获所有异常 -- 让未预期的异常传播出去
}

反模式

  • 抛出内置类型如 int 或字符串字面量 (E.14)
  • 按值捕获(切片风险)(E.15)
  • 静默吞掉错误的空 catch 块
  • 将异常用于流程控制 (E.3)
  • 基于全局状态如 errno 的错误处理 (E.28)

常量与不变性 (Con.*)

所有规则

规则概要
Con.1默认情况下,使对象不可变
Con.2默认情况下,使成员函数为 const
Con.3默认情况下,传递指向 const 的指针和引用
Con.4对构造后不会更改的值使用 const
Con.5对可在编译时计算的值使用 constexpr
// Con.1 到 Con.5: 默认不可变
class Sensor {
public:
    explicit Sensor(std::string id) : id_(std::move(id)) {}

    // Con.2: 默认使用 const 成员函数
    const std::string& id() const { return id_; }
    double last_reading() const { return reading_; }

    // 仅在需要修改时声明为非 const
    void record(double value) { reading_ = value; }

private:
    const std::string id_;  // Con.4: 构造后永不更改
    double reading_{0.0};
};

// Con.3: 通过 const 引用传递
void display(const Sensor& s) {
    std::cout << s.id() << ": " << s.last_reading() << '\n';
}

// Con.5: 编译时常量
constexpr double PI = 3.14159265358979;
constexpr int MAX_SENSORS = 256;

并发与并行 (CP.*)

关键规则

规则概要
CP.2避免数据竞争
CP.3最小化可写数据的显式共享
CP.4从任务的角度思考,而不是线程
CP.8不要使用 volatile 进行同步
CP.20使用 RAII,永远不要用裸的 lock()/unlock()
CP.21使用 std::scoped_lock 获取多个互斥量
CP.22持有锁时,永远不要调用未知代码
CP.42不要无条件的等待
CP.44记住给你的 lock_guard 和 unique_lock 命名
CP.100除非绝对必要,否则不要使用无锁编程

安全加锁

// CP.20 + CP.44: RAII 锁,始终命名
class ThreadSafeQueue {
public:
    void push(int value) {
        std::scoped_lock lock(mutex_); // C++17 CTAD
        data_.push(value);
        cond_var_.notify_one();
    }

    int pop() {
        std::unique_lock lock(mutex_);
        cond_var_.wait(lock, [this] { return !data_.empty(); });
        int value = data_.front();
        data_.pop();
        return value;
    }

private:
    std::mutex mutex_;
    std::queue<int> data_;
    std::condition_variable cond_var_;
};

反模式

  • 使用裸的 lock()/unlock() (CP.20 -- 使用 RAII)
  • 使用 volatile 进行同步 (CP.8 -- 使用 std::atomic)
  • 持有锁时阻塞或调用未知代码 (CP.22 -- 死锁风险)
  • 无条件等待(使用带有谓词的 condition_variable)(CP.42)
  • 在可能的情况下将任务模型当作线程模型使用 (CP.4)

模板与泛型编程 (T.*)

关键规则

规则概要
T.1使用模板来提升代码抽象
T.10为所有模板参数指定概念
T.20避免无需要求的“概念”
T.41在模板中,仅对模板参数进行最少量的假设
T.47避免包含

[已截断]

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

相关技能