2011:C++11 自動型別、Lambda 與移動語義——現代 C++ 誕生#
事件#
2011 年 9 月,C++11(ISO/IEC 14882:2011)正式發佈。這是 C++98 之後 13 年來最大的一次更新,被稱為「現代 C++」的起點——彷彿是一門新語言。
關鍵語法/特性#
auto:型別推論,由編譯器從初始值推導變數型別——省去冗長的迭代器型別宣告。- 右值引用與移動語義:
T&&、std::move——資源可以「搬移」而非複製,vector的搬移只付指標交換的成本。 - Lambda 運算式:
[](int x){ return x*2; }——匿名函式,可捕捉區域變數。 - 範圍 for:
for (auto& x : v)。 nullptr:型別安全的空指標,取代易出錯的NULL(整數 0)。constexpr:編譯期求值的函式與變數。- 可變參數樣板(variadic templates):
template<class... Args>——emplace_back、make_unique的基礎。 - 智慧指標:
unique_ptr、shared_ptr(移入標準庫)——RAII 管理記憶體。 - 執行緒庫:
std::thread、mutex、atomic、future——C++ 第一次有標準執行緒支援。 decltype、static_assert、委派建構子、override/final、enum class、統一初始化{}、std::initializer_list。
為何重要#
- 移動語義是革命:解決了「臨時物件被無謂深拷貝」的效能問題——C++ 效能從此不輸手寫的指標操作。
- Lambda 讓 STL 演算法真正可用:以前要定義 functor 類別才能傳行為,現在行內即可——
std::sort(v.begin(), v.end(), [](a,b){...})。 auto讓泛型程式碼可讀:map<string, vector<int>>::const_iterator一去不返。- 執行緒庫讓多核心時代有標準答案:C++98 時代並行只能靠平台 API(pthreads/Win32)。
理論與實用原因#
- 理論原因:移動語義源自「資源所有權轉移」的形式化(左值/右值二分,源自 C 的 value categories 理論);
auto源自 Hindley–Milner 型別推論;constexpr是純函式求值理論的落地。 - 實用原因:13 年的硬體革命(多核心、行動裝置)累積了太多缺口;Boost 社群(regex、thread、smart_ptr、function)已驗證了大部分設計——「Boost 是 C++11 的育成中心」。
彌補了什麼缺陷#
彌補了 C++98「型別宣告冗長、無匿名函式、臨時物件效能浪費、NULL 型別不安全、無標準執行緒、無編譯期求值」等一整個時代的缺陷——這是一次總清算。
程式範例#
auto:告別冗長的迭代器型別
#include <map>
#include <string>
#include <vector>
std::map<std::string, std::vector<int>> m;
void iter_old() {
// C++98 舊寫法:型別宣告冗長又易寫錯
std::map<std::string, std::vector<int>>::const_iterator it = m.begin();
}
void iter_new() {
// C++11:auto 由編譯器推論型別——同一個型別,一行搞定
auto it = m.begin(); // 型別為 std::map<string, vector<int>>::const_iterator
}
移動語義:搬移取代深拷貝
#include <string>
#include <utility>
#include <vector>
std::vector<std::string> make_big_vector(); // 產生大資料
void old_way() {
// C++98:臨時物件被無謂深拷貝——整個 vector 的字串逐一複製
std::vector<std::string> v = make_big_vector();
}
void new_way() {
// C++11:std::move 觸發搬移——只交換內部指標,常數時間
std::vector<std::string> a = make_big_vector();
std::vector<std::string> b = std::move(a); // a 之後不可再用
}
Lambda + STL:行內定義比較器
#include <algorithm>
#include <vector>
struct GreaterThan { // C++98 舊寫法:必須先定義 functor 結構
bool operator()(int a, int b) const { return a > b; }
};
int main() {
std::vector<int> v{3, 1, 4, 1, 5};
std::sort(v.begin(), v.end(), GreaterThan()); // 舊:要另寫類別
// C++11:Lambda 行內即可,還能用範圍 for 走訪
std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
for (int x : v) { /* ... */ }
}
nullptr 與智慧指標
#include <memory>
void use(int* p);
void f() {
int* a = NULL; // 舊:NULL 是整數 0,可能傳到 int 多載版本
int* b = nullptr; // C++11:型別安全的空指標,只匹配指標多載
// 智慧指標:RAII 管理,離開作用域自動釋放,不需手動 delete
auto u = std::unique_ptr<int>(new int(42)); // 獨佔所有權
auto s = std::shared_ptr<int>(new int(42)); // 共享所有權、引用計數
}