Compare commits

...

2 Commits

11 changed files with 330 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -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++ 已經改變很多了
<!--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 相比就麻煩很多。
但還是有在改變,試試看吧。

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

View File

@@ -0,0 +1,116 @@
---
slug: Windows Git Bash 改用 Zsh
title: Windows Git Bash 改用 Zsh
description:
toc: true
authors: []
tags: []
categories: []
series: []
date: 2026-01-16T00:00:00
lastmod: 2026-01-16T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---
[zsh](https://zh.wikipedia.org/zh-tw/Z_shell) 是一個很好用方便的 shell在 Linux 安裝非常方便,在 Windows 上如果有安裝 Git也可以透過 Git Bash 來使用,操作環境可以大幅貼近 Linux。
<!--more-->
## 0. 準備
- 要先裝 [Windows Terminal](https://apps.microsoft.com/detail/9n0dx20hk701?hl=zh-TW&gl=TW)
- 要安裝 [Git for Windows](https://git-scm.com/install/windows)
## 1. 安裝ZSH
### Windows
到 [Msys2 Package: zsh](https://packages.msys2.org/packages/zsh?repo=msys&variant=x86_64)下載
![msys2_zsh.png](images/msys2_zsh.png)
將壓縮檔內容複製到 Git 安裝目錄(一般而言是 `C:\Program Files\Git`
## 2. [安裝 oh-my-zsh](https://ohmyz.sh/)
```shell
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
```
## 3. 修改 `~/.bashrc`
Windows 的 user home 路徑是 `C:\Users\<user_name>`,所以要修改此目錄下的 `.bashrc`,如果沒有這個檔案就自己新增一個。
然後在 `C:\Users\<user_name>\.bashrc` 的最後加入:
```
if [ -t 1 ]; then
exec zsh
fi
```
這樣下次 bash 啟動的時候就會自動使用 zsh。
zsh 被啟動之後,我們的設定檔就變成了 `~/.zshrc` 而不是 `~/.bashrc` 了。
## 4. 安裝字型
等一下要使用的佈景主題會用很多字型裡的符號在UI上所以一般正常的字型沒辦法顯示只會看到方框裡面有一個問號。
所以我們要下載「修改過」的字型來顯示這些特殊符號。
到 [Nerd Font](https://www.nerdfonts.com/)下載你喜歡的字型。然後安裝到 Windows 裡面。這樣就可以了。
這裡假設你下載了 FiraCode Nerd Font。
![nerdfont_firacode.png](images/nerdfont_firacode.png)
## 5. 設定 Windows Terminal 的字型
打開 Windows Terminal`Ctrl+,` 進入設定畫面,左邊選 Git Bash ,然後在右邊選 "Appearance"
![windows_terminal_bash_appearance.png](images/windows_terminal_bash_appearance.png)
在 Font Face 那邊選擇 FiraCode Nerd Font。
![windows_terminal_bash_fontface.png](images/windows_terminal_bash_fontface.png)
## 6. 安裝 [powerlevel10k](https://github.com/romkatv/powerlevel10k)
[powerlevel10k](https://github.com/romkatv/powerlevel10k) 這個佈景主題讓 zsh 變得很好看
```shell
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
```
然後打開 `~/.zshrc` ,把佈景主題改成 powerlevel10k
找到 ` ZSH_THEME` 這一行,改成 `ZSH_THEME="powerlevel10k/powerlevel10k"`
![zsh_theme_setting.png](images/zsh_theme_setting.png)
然後重新打開 Windows Terminal打開 Git Bash ,就會出現 powerlevel10k 的 config 流程,你可以在這裡設定自己喜歡的風格樣式。
如果字型設定正確的話,會看到正確的符號,否則就是方框裡面有一個問號。
![powerlevel10k_config.png](images/powerlevel10k_config.png)
## 7. 安裝 plugin
這步不一定要做,看需求。
### 安裝 [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting)
這個 plugin 可以在 terminal 顯示 highlight syntax
安裝
```shell
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
```
然後要修改 `~/.zshrc`,在 `plugins` 加入 `zsh-syntax-highlighting`
![zsh_plugins_setting.png](images/zsh_plugins_setting.png)
### 安裝 [zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions)
這個 plugin 可以在輸入的時候提供已經輸入過的歷史命令或是相似的命令,讓你節省一點時間。
安裝
```
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
```
然後修改 `~/.zshrc`,在 `plugins` 加入 `zsh-autosuggestions`