1994:STL 標準模板庫問世——泛型程式設計革命#
事件#
1994 年,Alexander Stepanov 在 HP 開發的 STL(Standard Template Library) 被 ISO 委員會接受,納入 C++ 標準草案,1998 年成為正式標準的一部分。
關鍵語法/特性#
- 容器:
vector、list、map、set、deque。 - 迭代器(iterator):以「指標泛化」的概念連接容器與演算法。
- 演算法:
sort、find、transform、accumulate等上百個泛型演算法。 - 函式物件(functor) 與 配接器(adapter):以物件模擬函式,傳遞行為。
為何重要#
- STL 是史上第一個大規模的泛型函式庫:演算法與容器徹底解耦——
sort可以對任何容器的元素排序。 - 它確立了 C++ 泛型程式設計的風格:以迭代器為介面、以樣板為機制、以概念(concept)為隱性契約——2020 年 C++20 的 concepts 正是為了把這個「隱性契約」變成顯性語法。
- Stepanov 的「泛型程式設計」理論(與 Musser 合作)從此成為 C++ 的靈魂。
理論與實用原因#
- 理論原因:Stepanov 認為「演算法應該與資料結構分離」,其理論根源是抽象代數(群、環)與 Common Lisp 系列的泛型研究;迭代器概念源自「指標是所有序列操作的共同介面」。
- 實用原因:在 STL 之前,每個專案都要重寫自己的鏈結串列與排序——STL 讓「標準容器」成為常識。
彌補了什麼缺陷#
彌補了 C++ 樣板誕生後「有泛型機制、無泛型函式庫」的缺陷;也彌補了 C「容器與演算法绑死、無法複用」的缺陷。
程式範例#
STL 之前的舊寫法:每個專案都要自己寫鏈結串列與排序,且演算法绑死在自己的資料結構上,無法複用:
/* 每個專案都要重寫的程式碼 */
struct node { int val; struct node* next; };
void list_sort(struct node* head); // 只能排自己的 node 串列
struct node* list_find(struct node* head, int v);
// 換成 double 或另一種容器?全部重寫一遍
新寫法(1994 STL):容器、迭代器、泛型演算法、函式物件一次到位:
#include <vector>
#include <map>
#include <algorithm> // sort, find
#include <numeric> // accumulate
#include <iostream>
int main() {
// 容器:std::vector 取代手寫陣列/串列
std::vector<int> v = {5, 3, 1, 4, 2};
// 泛型演算法:一行搞定排序——STL 前要自己寫幾十行
std::sort(v.begin(), v.end()); // 1 2 3 4 5
// 迭代器:以「指標泛化」連接容器與演算法
auto it = std::find(v.begin(), v.end(), 4);
if (it != v.end()) std::cout << "found " << *it << "\n";
// accumulate:對任何容器通用
int sum = std::accumulate(v.begin(), v.end(), 0); // 15
std::cout << "sum = " << sum << "\n";
// map:紅黑樹實作的關聯容器
std::map<std::string, int> ages;
ages["Alice"] = 30;
std::cout << ages["Alice"] << "\n";
return 0;
}
演算法對任何容器通用——同一個 sort 也能排 list,因為演算法只依賴迭代器介面:
#include <list>
#include <algorithm>
std::list<int> lst = {5, 3, 1};
lst.sort(); // list 自帶的成員版(串列不支援隨機存取)
// std::vector 用的 std::sort(v.begin(), v.end()) 也是同一套泛型思維
函式物件(functor):以物件模擬函式,把「行為」當參數傳遞:
#include <vector>
#include <algorithm>
struct GreaterThan {
int bound;
bool operator()(int x) const { return x > bound; } // 讓物件像函式一樣被呼叫
};
std::vector<int> v = {1, 7, 3, 9};
auto n = std::count_if(v.begin(), v.end(), GreaterThan{5}); // n == 2