Communitygithub.com

C++ 編碼標準 (C++ Core Guidelines)

基於 C++ Core Guidelines (isocpp.github.io) 的 C++ 編碼標準。用於編寫、審查或重構 C++ 程式碼,以強制實施現代、安全且慣用的實務做法。

C++ 編碼標準 (C++ Core Guidelines) 是什麼?

此技能提供一套全面的 C++ 編碼標準,源自官方 C++ Core Guidelines,專為現代 C++(C++17/20/23)設計。其核心目標是透過強制執行六大跨領域原則(包括 RAII、預設不可變性、型別安全、表達意圖、最小化複雜度以及值語義)來提升型別安全性、資源安全性、不可變性和程式碼清晰度。此技能適用於任何 C++ 開發階段,包括編寫新類別與函式、審查既有程式碼、進行架構決策,以及在像是 `enum` 與 `enum class` 或裸指標與智慧指標之間選擇語言特性時。它透過詳細的表格、最佳實踐範例(DO)和反模式警示(DON'T)來組織規則,涵蓋哲學與介面(P.*, I.*)、函式(F.*)、類別(C.*)、資源管理(R.*)、運算式與陳述式(ES.*)、錯誤處理(E.*)、常數與不可變性(Con.*)及並行與平行處理(CP.*)等關鍵主題。此技能支援 Claude Code 和 Cursor 等 AI 編碼代理平台,透過將標準規則直接編碼到 SKILL.md 檔案中,使 AI 能夠在程式碼生成過程中自動套用這些現代 C++ 慣例,從而建立更安全、更易於維護的程式碼庫。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/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保持函式參數數量較少

DO

// P.10 + I.4:不可變、強型別介面
struct Temperature {
    double kelvin;
};

Temperature boil(const Temperature& water);

DON'T

// 弱介面:所有權不明確,單位不明確
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基底類別解構函式:應為 public virtual 或 protected non-virtual
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 -- 異常安全隱患)
  • 在 unique_ptr 就足夠的情況下使用 shared_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解構函式、釋放和交換永遠不能失敗
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)
  • 默默吞掉錯誤的空捕獲區塊
  • 使用異常進行流程控制 (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以任務(task)而非執行緒(thread)的方式思考
CP.8不要使用 volatile 進行同步
CP.20使用 RAII,永遠不要用裸 lock()/unlock()
CP.21使用 std::scoped_lock 獲取多個互斥鎖
CP.22在持有鎖時,永遠不要呼叫未知的程式碼
CP.42不要無條件等待
CP.44記得為你的 lock_guards 和 unique_locks 命名
CP.100除非萬不得已,否則不要使用無鎖編程

安全鎖定

// CP.20 + CP.44:RAII 鎖,始終命名
#include <queue>
#include <mutex>
#include <condition_variable>

template<typename T>
class ThreadSafeQueue {
public:
    void push(T value) {
        std::scoped_lock lock(mutex_);  // CP.21:安全獲取
        queue_.push(std::move(value));
        cond_.notify_one();
    }

    T pop() {
        std::unique_lock lock(mutex_);
        cond_.wait(lock, [this] { return !queue_.empty(); }); // CP.42:條件等待
        T value = std::move(queue_.front());
        queue_.pop();
        return value;
    }

private:
    std::queue<T> queue_;
    std::mutex mutex_;
    std::condition_variable cond_;
};

反模式

  • 使用 volatile 進行執行緒間同步(使用 std::atomic)(CP.8)
  • 裸 lock()/unlock() 模式(忘記解鎖)(CP.20)
  • 在持有鎖時阻塞或呼叫使用者程式碼 (CP.22)
  • 使用 shared_ptr 線上程之間共享可變資料(改為考慮拷貝或 unique_ptr)(CP.31)

模板與泛型編程 (T.*)

關鍵規則

規則摘要
T.10為所有模板引數指定概念
T.20避免「無概念」的模板
T.41僅在模板中需要時才使用前置宣告
T.47避免高度可見的未受檢模板
T.120僅對真正的對映使用模板元編程

DO

// T.10:使用概念
#include <concepts>

template<std::integral T>
T square(T value) {
    return value * value;
}

DON'T

// T.20:「無概念」模板(接受任何東西)
template<typename T>
T max(T a, T b) {  // 與其合作的操作不明確
    return a > b ? a : b;
}

標準函式庫 (SL.*)

關鍵規則

規則摘要
SL.1使用標準函式庫;不要重新發明輪子
SL.2偏好標準函式庫而非其他函式庫
SL.3避免非標準擴展
SL.4以便利且安全的方式使用標準函式庫
SL.10偏好 std::string 而非 char[]
SL.20使用 std::span 或 std::string_view 表示一系列元素或字元
SL.30使用 std::optional 表示可能未初始化的值
SL.40使用 std::variant 表示型別安全的聯合體
SL.50使用 std::expected 表示帶有預期結果的函式(C++23)
SL.60偏好 std::array 或 std::vector 而非 C 風格的陣列

DO

// SL.30 + SL.40:現代安全型別
std::optional<int> find_value(const std::vector<int>& data, int target);

using ErrorCode = int;
std::variant<int, ErrorCode> compute_risk(const std::string& profile);

// SL.20:用於檢視的非擁有介面
void process_text(std::string_view input);

// SL.60:用於固定大小陣列的 std::array
std::array<double, 4> coefficients{1.0, 2.0, 3.0, 4.0};

DON'T

// SL.10:避免舊式 C 字串
char buffer[256];

// SL.60:避免 C 風格陣列
int data[100];

實作提示

編譯器標誌(GCC/Clang)

-Wall -Wextra -Wpedantic -Werror
-Wnon-virtual-dtor -Wold-style-cast -Wcast-align
-Woverloaded-virtual -Wconversion -Wsign-conversion
-Wmisleading-indentation -Wduplicated-cond -Wnull-dereference

工具

  • clang-tidy:自動化程式碼檢查(包含 cppcoreguidelines-* 檢查組)
  • clang-format:自動格式化(基於 .clang-format)
  • cppcheck:靜態分析
  • AddressSanitizer / UndefinedBehaviorSanitizer:執行時期檢查

clang-tidy 配置範例

Checks: '
  cppcoreguidelines-*,
  modernize-*,
  performance-*,
  readability-*,
  bugprone-*,
  -cppcoreguidelines-avoid-magic-numbers,
  -readability-magic-numbers'

結論

遵循這些標準可以建立更安全、更易於維護、更具表現力的 C++ 程式碼。關鍵要點:

  1. 自動管理資源(RAII)
  2. 預設使用 const 和值語義
  3. 使用型別系統在編譯時防止錯誤
  4. 編寫表達意圖的簡單程式碼
  5. 偏好標準函式庫而非自製解決方案
  6. 注意異常安全和執行緒安全

當在有約束的環境(嵌入式、即時系統)中偏離這些規則時,始終記錄理由。

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/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

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.

相關技能