diff --git a/content/posts/2026/2026-01-04_用 Modern C++ 的方式寫程式吧/featured.png b/content/posts/2026/2026-01-04_用 Modern C++ 的方式寫程式吧/featured.png new file mode 100644 index 0000000..aa5dec1 Binary files /dev/null and b/content/posts/2026/2026-01-04_用 Modern C++ 的方式寫程式吧/featured.png differ diff --git a/content/posts/2026/2026-01-04_用 Modern C++ 的方式寫程式吧/index.md b/content/posts/2026/2026-01-04_用 Modern C++ 的方式寫程式吧/index.md new file mode 100644 index 0000000..ecd8c4f --- /dev/null +++ b/content/posts/2026/2026-01-04_用 Modern C++ 的方式寫程式吧/index.md @@ -0,0 +1,214 @@ +--- +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++ 已經改變很多了 + + + +### 歷史包袱的重量 + +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(size); +// 自動管理記憶體,無需手動 delete +``` + +**使用 Smart Pointer** + +- `std::unique_ptr`:獨佔所有權 +- `std::shared_ptr`:共享所有權 +- `std::weak_ptr`:弱引用,避免循環依賴 + +### 2. 用容器取代原生陣列 + +```cpp +// 危險的 C 陣列 +int arr[100]; // 無邊界檢查,容易越界 + +// 安全的 Modern C++ 容器 +std::array arr; // 編譯時大小固定 +std::vector vec; // 動態大小 +``` + +### 3. 自動型別推導 + +C++ 11 開始支援 [`auto`](https://en.cppreference.com/w/cpp/keyword/auto.html) 關鍵字 + +```cpp +// 舊的方式,冗長的型別宣告 +std::vector::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 findValue(const std::map& 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& 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 using Handler = std::function; +Handler intHandler; +``` + +用 `using` 來簡化 `std::function` 的例子。例如說我們的參數是一個 callback function +```cpp +void setOnProgress(std::function callback) { + progressCb = callback; +} + +// 用 using 簡化 +using ProgressCallback = std::function; + +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(); // 直接收進 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 相比就麻煩很多。 +但還是有在改變,試試看吧。