---
name: cpp-coding-standards
description: 基於 C++ Core Guidelines (isocpp.github.io) 的 C++ 編碼標準。在編寫、審查或重構 C++ 程式碼時使用，以強制執行現代、安全且符合慣用法 (Idiomatic) 的實踐。
---

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

衍生自 [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) 的現代 C++ (C++17/20/23) 綜合編碼標準。強化型別安全、資源安全、不可變性與清晰度。

## 何時使用

- 撰寫新 C++ 程式碼 (類別、函式、範本)。
- 審查或重構現有的 C++ 程式碼。
- 在 C++ 專案中做出架構決策。
- 在 C++ 程式碼庫中強制執行一致的風格。
- 在語言特性間做選擇 (例如：`enum` vs `enum class`、原始指標 vs 智慧指標)。

### 何時「不」使用

- 非 C++ 專案。
- 無法採用現代 C++ 特性的遺留 C 程式碼庫。
- 特定指南與硬體限制衝突的嵌入式/裸機環境 (請選擇性地調整使用)。

## 橫切原則 (Cross-Cutting Principles)

這些主題貫穿整個指南並構成基礎：

1. **RAII 無處不在** (P.8, R.1, E.6, CP.20)：將資源生命週期與物件生命週期綁定。
2. **預設不可變性** (P.10, Con.1-5, ES.25)：從 `const`/`constexpr` 開始；可變性（Mutability）是例外。
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)：優先選擇以值回傳與作用域物件 (Scoped objects)。

## 哲學與介面 (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)

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

Temperature boil(const Temperature& water);
```

### 應避免的做法 (DON'T)

```cpp
// 弱介面：所有權不明確、單位不明確
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** | 優先選用純函式 (Pure functions) |
| **F.16** | 對於「輸入 (in)」參數，低成本複製之型別以值傳遞，其餘以 `const&` 傳遞 |
| **F.20** | 對於「輸出 (out)」值，優先選擇回傳值而非輸出參數 |
| **F.21** | 若要回傳多個輸出值，優先回傳一個 struct |
| **F.43** | 絕不回傳指向區域物件的指標或參照 |

### 參數傳遞

```cpp
// F.16：低成本型別傳值，其餘傳 const&
void print(int x);                           // 低成本：傳值
void analyze(const std::string& data);       // 高成本：傳 const&
void transform(std::string s);               // 接收端：傳值 (將觸發 move)

// F.20 + F.21：使用回傳值，而非輸出參數
struct ParseResult {
    std::string token;
    int position;
};

ParseResult parse(std::string_view input);   // 推薦 (GOOD)：回傳 struct

// 錯誤範例 (BAD)：輸出參數
void parse(std::string_view input,
           std::string& token, int& pos);    // 應避免此做法
```

### 純函式與 constexpr

```cpp
// F.4 + F.8：純函式，盡可能使用 constexpr
constexpr int factorial(int n) noexcept {
    return (n <= 1) ? 1 : n * factorial(n - 1);
}

static_assert(factorial(5) == 120);
```

### 反模式 (Anti-Patterns)

- 函式回傳 `T&&` (F.45)。
- 使用 `va_arg` / C 風格變長參數 (F.55)。
- 在傳遞給其他執行緒的 Lambda 中以傳參照方式擷取 (F.53)。
- 回傳 `const T`，會抑制搬移語義 (Move semantics) (F.49)。

## 類別與類別階層 (C.*)

### 關鍵規則

| 規則 | 摘要 |
|------|---------|
| **C.2** | 若存在不變式 (Invariant) 則使用 `class`；若資料成員獨立變化則使用 `struct` |
| **C.9** | 最小化成員的公開暴露 |
| **C.20** | 若可避免定義預設操作，就不要定義 (Rule of Zero) |
| **C.21** | 若定義或 `=delete` 任何 copy/move/destructor，應處理全部 (Rule of Five) |
| **C.35** | 基底類別解構子：public virtual 或 protected non-virtual |
| **C.41** | 建構子應建立一個完整初始化的物件 |
| **C.46** | 將單參數建構子宣告為 `explicit` |
| **C.67** | 多型類別應抑制公開的 copy/move |
| **C.128** | 虛擬函式：精確指定 `virtual`、`override` 或 `final` 其中之一 |

### Rule of Zero (零原則)

```cpp
// C.20：讓編譯器生成特殊成員
struct Employee {
    std::string name;
    std::string department;
    int id;
    // 無需解構子、copy/move 建構子或賦值運算子
};
```

### Rule of Five (五原則)

```cpp
// 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_;
};
```

### 類別階層 (Class Hierarchy)

```cpp
// 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)。
- 在非平凡 (Non-trivial) 型別上使用 `memset`/`memcpy` (C.90)。
- 為虛擬函式與其實現提供不同的預設參數 (C.140)。
- 將資料成員設為 `const` 或參照，這會抑制 move/copy (C.12)。

## 資源管理 (R.*)

### 關鍵規則

| 規則 | 摘要 |
|------|---------|
| **R.1** | 使用 RAII 自動管理資源 |
| **R.3** | 原始指標 (`T*`) 不具備所有權 |
| **R.5** | 優先選用作用域物件；不要進行非必要的堆積配置 (Heap-allocate) |
| **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` |

### 智慧指標用法

```cpp
// R.11 + R.20 + R.21：RAII 搭配智慧指標
auto widget = std::make_unique<Widget>("config");  // 唯一所有權
auto cache  = std::make_shared<Cache>(1024);        // 共享所有權

// R.3：原始指標 = 非擁有式觀察者 (Non-owning observer)
void render(const Widget* w) {  // 不擁有 w
    if (w) w->draw();
}

render(widget.get());
```

### RAII 模式

```cpp
// R.1：資源獲取即初始化 (Resource acquisition is initialization)
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_;
};
```

### 反模式

- 赤裸的 (Naked) `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** | 對於 `const` 變數的複雜初始化使用 Lambda |
| **ES.45** | 避免魔術常數；使用符號常數 |
| **ES.46** | 避免窄化/有損的算術轉型 |
| **ES.47** | 使用 `nullptr` 而非 `0` 或 `NULL` |
| **ES.48** | 避免強行轉型 (Casts) |
| **ES.50** | 不要轉型掉 `const` (Cast away const) |

### 初始化

```cpp
// 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** | 傳值抛出，傳引用 (by reference) 捕捉 |
| **E.16** | 解構子、釋放操作與 swap 絕不可失敗 |
| **E.17** | 不要試圖在每個函式中捕捉所有異常 |

### 異常階層 (Exception Hierarchy)

```cpp
// 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)。
- 以傳值方式捕捉 (有切割 Slicing 風險) (E.15)。
- 空的 catch 區塊默默吞掉錯誤。
- 將異常效於流程控制 (E.3)。
- 基於全域狀態 (如 `errno`) 進行錯誤處理 (E.28)。

## 常數與不可變性 (Con.*)

### 所有規則

| 規則 | 摘要 |
|------|---------|
| **Con.1** | 預設情況下，使物件不可變 |
| **Con.2** | 預設情況下，使成員函式為 `const` |
| **Con.3** | 預設情況下，傳遞指標與參照至 `const` |
| **Con.4** | 對建構後內容不變的數值使用 `const` |
| **Con.5** | 對可在編譯時計算的數值使用 `constexpr` |

```cpp
// 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** | 避免資料競爭 (Data races) |
| **CP.3** | 最小化可寫入資料的明確共享 |
| **CP.4** | 以「任務」而非「執行緒」的角度思考 |
| **CP.8** | 不要使用 `volatile` 進行同步 |
| **CP.20** | 使用 RAII，絕不單獨使用 `lock()`/`unlock()` |
| **CP.21** | 使用 `std::scoped_lock` 獲取多個互斥鎖 (Mutexes) |
| **CP.22** | 持有鎖時絕不呼叫未知程式碼 |
| **CP.42** | 不要無條件等待 |
| **CP.44** | 務必為您的 `lock_guard` 與 `unique_lock` 命名 |
| **CP.100** | 除非絕對必要，否則不要使用無鎖 (Lock-free) 程式開發 |

### 安全加鎖

```cpp
// CP.20 + CP.44：RAII 鎖，務必命名
class ThreadSafeQueue {
public:
    void push(int value) {
        std::lock_guard<std::mutex> lock(mutex_);  // CP.44：必須命名！
        queue_.push(value);
        cv_.notify_one();
    }

    int pop() {
        std::unique_lock<std::mutex> lock(mutex_);
        // CP.42：務必帶條件等待
        cv_.wait(lock, [this] { return !queue_.empty(); });
        const int value = queue_.front();
        queue_.pop();
        return value;
    }

private:
    std::mutex mutex_;             // CP.50：互斥鎖應與其保護的資料放在一起
    std::condition_variable cv_;
    std::queue<int> queue_;
};
```

### 多重互斥鎖

```cpp
// CP.21：使用 std::scoped_lock 處理多個互斥鎖 (無死結風險)
void transfer(Account& from, Account& to, double amount) {
    std::scoped_lock lock(from.mutex_, to.mutex_);
    from.balance_ -= amount;
    to.balance_ += amount;
}
```

### 反模式

- 使用 `volatile` 進行同步 (CP.8 — 它僅用於硬體 I/O)。
- 分離 (Detach) 執行緒 (CP.26 — 生命週期管理會變得幾乎不可能)。
- 未命名的 Lock guards：`std::lock_guard<std::mutex>(m);` 會立即銷毀 (CP.44)。
- 在呼叫回呼函式 (Callbacks) 時持有鎖 (CP.22 — 有死結風險)。
- 在不具備深厚專業知識的情況下進行無鎖程式開發 (CP.100)。

## 範本與泛型程式開發 (T.*)

### 關鍵規則

| 規則 | 摘要 |
|------|---------|
| **T.1** | 使用範本提升抽象層級 |
| **T.2** | 使用範本針對多種參數型別表達演算法 |
| **T.10** | 為所有範本參數指定概念 (Concepts) |
| **T.11** | 盡可能使用標準概念 |
| **T.13** | 對於簡單概念優先選用簡寫記法 |
| **T.43** | 優先選用 `using` 而非 `typedef` |
| **T.120** | 僅在絕對必要時使用範本元編程 (Template metaprogramming) |
| **T.144** | 不要特化 (Specialize) 函式範本 (應改用多載 Overload) |

### 概念 (Concepts - C++20)

```cpp
#include <concepts>

// T.10 + T.11：使用標準概念約束範本
template<std::integral T>
T gcd(T a, T b) {
    while (b != 0) {
        a = std::exchange(b, a % b);
    }
    return a;
}

// T.13：概念簡寫語法
void sort(std::ranges::random_access_range auto& range) {
    std::ranges::sort(range);
}

// 針對領域特定約束的自定義概念
template<typename T>
concept Serializable = requires(const T& t) {
    { t.serialize() } -> std::convertible_to<std::string>;
};

template<Serializable T>
void save(const T& obj, const std::string& path);
```

### 反模式

- 在可見名稱空間中使用無約束範本 (T.47)。
- 特化函式範本而非使用多載 (T.144)。
- 在 `constexpr` 足以勝任的情況下使用範本元編程 (T.120)。
- 使用 `typedef` 而非 `using` (T.43)。

## 標準函式庫 (SL.*)

### 關鍵規則

| 規則 | 摘要 |
|------|---------|
| **SL.1** | 盡可能使用函式庫 |
| **SL.2** | 優先選用標準函式庫而非其他函式庫 |
| **SL.con.1** | 優先選用 `std::array` 或 `std::vector` 而非 C 陣列 |
| **SL.con.2** | 預設情況下優先選用 `std::vector` |
| **SL.str.1** | 使用 `std::string` 擁有字元序列 |
| **SL.str.2** | 使用 `std::string_view` 參照字元序列 |
| **SL.io.50** | 避免使用 `endl` (請用 `'\n'` — `endl` 會強制執行 flush) |

```cpp
// SL.con.1 + SL.con.2：優先選用 vector/array 而非 C 陣列
const std::array<int, 4> fixed_data{1, 2, 3, 4};
std::vector<std::string> dynamic_data;

// SL.str.1 + SL.str.2：string 擁有資料，string_view 觀察資料
std::string build_greeting(std::string_view name) {
    return "Hello, " + std::string(name) + "!";
}

// SL.io.50：使用 '\n' 而非 endl
std::cout << "結果: " << value << '\n';
```

## 列舉 (Enum.*)

### 關鍵規則

| 規則 | 摘要 |
|------|---------|
| **Enum.1** | 優先選用列舉而非巨集 (Macros) |
| **Enum.3** | 優先選用 `enum class` 而非一般 `enum` |
| **Enum.5** | 不要對列舉值使用 全大寫 (ALL_CAPS) |
| **Enum.6** | 避免匿名列舉 |

```cpp
// Enum.3 + Enum.5：強型別列舉，不使用全大寫
enum class Color { red, green, blue };
enum class LogLevel { debug, info, warning, error };

// 錯誤範例 (BAD)：一般列舉會洩漏名稱，全大寫會與巨集衝突
enum { RED, GREEN, BLUE };           // 違反 Enum.3 + Enum.5 + Enum.6
#define MAX_SIZE 100                  // 違反 Enum.1 — 請用 constexpr
```

## 來源檔案與命名 (SF.*, NL.*)

### 關鍵規則

| 規則 | 摘要 |
|------|---------|
| **SF.1** | 程式碼檔案使用 `.cpp`，介面檔案使用 `.h` |
| **SF.7** | 不要在標頭檔的全域範圍撰寫 `using namespace` |
| **SF.8** | 為所有 `.h` 檔案使用 `#include` 防護 |
| **SF.11** | 標頭檔應具備自給自足 (Self-contained) 特性 |
| **NL.5** | 避免在名稱中編碼型別資訊 (不使用匈牙利命名法) |
| **NL.8** | 使用一致的命名風格 |
| **NL.9** | 僅對巨集名稱使用 全大寫 (ALL_CAPS) |
| **NL.10** | 優先選用 `underscore_style` (底線風格) 名稱 |

### 標頭檔防護 (Header Guard)

```cpp
// SF.8：Include 防護 (或使用 #pragma once)
#ifndef PROJECT_MODULE_WIDGET_H
#define PROJECT_MODULE_WIDGET_H

// SF.11：自給自足 — 包含此標頭檔所需的所有內容
#include <string>
#include <vector>

namespace project::module {

class Widget {
public:
    explicit Widget(std::string name);
    const std::string& name() const;

private:
    std::string name_;
};

}  // namespace project::module

#endif  // PROJECT_MODULE_WIDGET_H
```

### 命名規範

```cpp
// NL.8 + NL.10：一致的底線風格 (underscore_style)
namespace my_project {

constexpr int max_buffer_size = 4096;  // NL.9：非全大寫 (因為這不是巨集)

class tcp_connection {                 // 底線風格類別名
public:
    void send_message(std::string_view msg);
    bool is_connected() const;

private:
    std::string host_;                 // 成員變數使用後綴底線
    int port_;
};

}  // namespace my_project
```

### 反模式

- 在標頭檔全域範圍使用 `using namespace std;` (SF.7)。
- 依賴包含順序的標頭檔 (SF.10, SF.11)。
- 匈牙利命名法，如 `strName`、`iCount` (NL.5)。
- 對巨集以外的任何內容使用全大寫 (NL.9)。

## 效能 (Per.*)

### 關鍵規則

| 規則 | 摘要 |
|------|---------|
| **Per.1** | 無理由不優化 |
| **Per.2** | 不要過早優化 |
| **Per.6** | 沒有數據測量，不對效能下結論 |
| **Per.7** | 設計應允許優化 |
| **Per.10** | 依賴靜態型別系統 |
| **Per.11** | 將運算從執行時期移至編譯時期 |
| **Per.19** | 記憶體存取應具備可預測性 |

### 指導原則

```cpp
// Per.11：盡可能在編譯時期計算
constexpr auto lookup_table = [] {
    std::array<int, 256> table{};
    for (int i = 0; i < 256; ++i) {
        table[i] = i * i;
    }
    return table;
}();

// Per.19：優先選用連續資料以維持快取友善性
std::vector<Point> points;           // 推薦 (GOOD)：連續存取
std::vector<std::unique_ptr<Point>> indirect_points; // 錯誤 (BAD)：指標追蹤
```

### 反模式

- 在沒有分析 (Profiling) 數據的情況下進行優化 (Per.1, Per.6)。
- 選擇「聰明」的低階程式碼而非清晰的抽象 (Per.4, Per.5)。
- 忽視資料佈局與快取行為 (Per.19)。

## 快速參考檢核清單

在將 C++ 工作標記為完成之前：

- [ ] 無原始的 `new`/`delete` — 使用智慧指標或 RAII (R.11)
- [ ] 物件在宣告時即初始化 (ES.20)
- [ ] 變數預設使用 `const`/`constexpr` (Con.1, ES.25)
- [ ] 成員函式盡可能設為 `const` (Con.2)
- [ ] 使用 `enum class` 而非一般 `enum` (Enum.3)
- [ ] 使用 `nullptr` 而非 `0`/`NULL` (ES.47)
- [ ] 無窄化轉型 (ES.46)
- [ ] 無 C 風格轉型 (ES.48)
- [ ] 單參數建構子皆設定為 `explicit` (C.46)
- [ ] 套用零原則 (Rule of Zero) 或五原則 (Rule of Five) (C.20, C.21)
- [ ] 基底類別解構子為 public virtual 或 protected non-virtual (C.35)
- [ ] 範本使用概念 (Concepts) 約束 (T.10)
- [ ] 不在標頭檔的全域範圍使用 `using namespace` (SF.7)
- [ ] 標頭檔具備 Include 防護且自給自足 (SF.8, SF.11)
- [ ] 加鎖使用 RAII (`scoped_lock`/`lock_guard`) (CP.20)
- [ ] 異常為自定義型別，傳值抛出，傳引用捕捉 (E.14, E.15)
- [ ] 使用 `'\n'` 而非 `std::endl` (SL.io.50)
- [ ] 不使用魔術數字 (ES.45)
