---
slug: "[C++ 筆記] 用 Modern C++ 的方式寫程式吧"
title: "[C++ 筆記] 用 Modern C++ 的方式寫程式吧"
description:
toc: true
authors:
    - awin
tags:
    - c++
categories:
    - Programming
series:
    - C++ 筆記
date: 2026-01-04T00:00:00
lastmod: 2026-01-04T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---

## Modern C++ 已經改變很多了

<!--more-->

### 歷史包袱的重量

C++ 一直在相容性上不遺餘力，舊的語法能跑，新的語法與關鍵字又一直疊加，最後呈現出來的就是複雜。作為一個長久以來的使用者，看著其他程式語言的崛起與更新，雖然在理性上很能夠理解，但是情感上還是會想掙扎一下，讓我們看看 Modern C++ 改變的那一面，拋棄到舊的習慣，讓我們可以在不失去效能的情況下，用「比較輕鬆」的方式來寫 C++。

## Modern C++ 的改變

### 1. 記憶體管理

**告別手動記憶體管理（`new`/`delete`）**

```cpp
// 舊式 C/C++ 方式
BigBuffer* buffer = new BigBuffer(size);
// ... 使用 buffer
delete buffer;  // 容易忘記，造成記憶體洩漏

// Modern C++ 方式
auto buffer = std::make_unique<BigBuffer>(size);
// 自動管理記憶體，無需手動 delete
```

**使用 Smart Pointer**

- `std::unique_ptr`：獨佔所有權
- `std::shared_ptr`：共享所有權
- `std::weak_ptr`：弱引用，避免循環依賴

### 2. 用容器取代原生陣列

```cpp
// 危險的 C 陣列
int arr[100];  // 無邊界檢查，容易越界

// 安全的 Modern C++ 容器
std::array<int, 100> arr;    // 編譯時大小固定
std::vector<int> vec;        // 動態大小
```

### 3. 自動型別推導

C++ 11 開始支援 [`auto`](https://en.cppreference.com/w/cpp/keyword/auto.html) 關鍵字

```cpp
// 舊的方式，冗長的型別宣告
std::vector<std::string>::iterator it = vec.begin();

// 簡潔的 auto
auto it = vec.begin();

// 結構化綁定（C++17）
auto [key, value] = map_pair;
```

### 4. 現代迴圈語法

```cpp
// 傳統 C 風格迴圈
for (int i = 0; i < arr.size(); ++i) {
    process(arr[i]);
}

// Modern C++ 範圍迴圈
for (const auto& elem : arr) {
    process(elem);
}
```

### 5. Lambda 表達式

```cpp
// 傳統函式物件
struct Comparator {
    bool operator()(int a, int b) const {
        return a < b;
    }
};

// Modern C++ Lambda
auto compare = [](int a, int b) { return a < b; };
```

## Modern C++ 的其他好東西

### 使用 `std::optional` 明確表達「可能為空」的情況

```cpp
std::optional<int> findValue(const std::map<int, int>& mapping, int key) {
    auto it = mapping.find(key);
    if (it != mapping.end()) {
        return it->second;  // 找到了，返回值
    }
    return std::nullopt;    // 沒找到，返回空值
}

// 使用前必須檢查
auto value = findValue(numbers, 42);
if (value.has_value()) {
    std::cout << "Found value：" << value.value() << std::endl;
}
```

像 Python 可以 `return None` 來表示空值，`std::nullopt` 也提供了一個表達空值的方式。
傳統的方式只能像是：
```cpp
bool findResult(const std::vector<int>& mapping, int target, int& result) {
    for (const auto& value : mapping) {
        if (value == target) {
            result = value;  // 找到了，設置結果
            return true;     // 返回成功
        }
    }
    return false;            // 沒找到，返回失敗
}
```

### `constexpr` 可以在編譯時計算

```cpp
constexpr int factorial(int n) {
    return (n <= 1) ? 1 : n * factorial(n - 1);
}

// 在編譯時就能計算出結果
constexpr int fact5 = factorial(5);  // 編譯時計算為 120
```
### 用 `using` 簡化程式

`using`（稱為型別別名，Type Alias）和 `typedef` 的功能基本上是一樣的：它們都是為現有的型別建立一個「別名」，而不是建立新的型別。

- **`using`：** `using [新名字] = [舊型別];`
- **`typedef`：** `typedef [舊型別] [新名字];` // 比較不直覺

`using` 有一個 `typedef` 做不到的是模板別名（Template Alias）。

例如
```cpp
template <typename T> using Handler = std::function<void(const T&)>;
Handler<int> intHandler;
```

用 `using` 來簡化 `std::function` 的例子。例如說我們的參數是一個 callback function
```cpp
void setOnProgress(std::function<void(double, size_t)> callback) {
    progressCb = callback;
}

// 用 using 簡化
using ProgressCallback = std::function<void(double percentage, size_t bytesSent)>;

void setOnProgress(ProgressCallback callback) {
	progressCb = callback;
}
```

### 表達力

Modern C++ 讓程式碼更接近自然語言：

```cpp
auto result = numbers
    | std::views::filter([](int x) { return x % 2 == 0; }) // 挑偶數
    | std::views::transform([](int x) { return x * x; })   // 轉平方
    | std::ranges::to<std::vector>();                      // 直接收進 vector
```

C++23 加入了 [`std::ranges::to`](https://en.cppreference.com/w/cpp/ranges/to.html)
更重要的是不用再寫一堆 Iterator。

### 效能

Modern C++ 的效能提升，精確來說是實踐了 **「零成本抽象（Zero-overhead abstraction）」**。

- **`constexpr`**：這真的很好用。能把計算直接塞進編譯階段，執行時完全不用花 CPU 時間。到了 C++20 更有 `consteval` 強制編譯期計算。
- **移動語意 (Move Semantics)**：這是 C++ 的續命符。它解決了以前回傳大型物件時，為了怕拷貝太慢得傳指標或寫得扭扭捏捏的問題。現在直接 `return` 沒負擔。

## 試試看吧，漸進式升級

一開始先試著用 `std::array` 或 `std::vector` 來取代傳統的 array。
然後用 smart pointer 來取代 `new/delete`。
過程中用 `auto` 來少打一些字。
用 `using` 來簡化落落長的型別。
用 Lambda 來簡化 callback（不用在遠遠的地方定義 function）。

試試看，當冗長的 code 變得清爽，思路也比較不容易打結。

## 最後

雖然 C++ 還是有很多可以改進的地方，例如 package 的使用跟 Python 相比就麻煩很多。
但還是有在改變，試試看吧。
