C++ std::string 經典實作採用 Copy-On-Write (COW):複製字串時僅增加引用計數,直到發生寫入才真正拷貝資料。但鮮為人知的是,單純的讀取操作(如 operator[] 或迭代器)也可能導致 COW 失效,造成效能劇烈下降。
string base(10*1024*1024, 'x'); // 10MB
// 100 次複製,未修改:極快(<1ms)
for (int i=0; i<100; ++i) { string copy = base; }
// 100 次複製並修改首字元:約 4-5 秒(觸發深拷貝)
for (int i=0; i<100; ++i) { string copy = base; copy[0]='y'; }
string base(10*1024*1024, 'x');
char c = base[0]; // 僅讀取首字元
// 隨後 100 次複製:同樣耗時 4-5 秒!
for (int i=0; i<100; ++i) { string copy = base; }
operator[] 的承諾operator[] 回傳 char&(非 const 版本),允許呼叫端直接修改內部緩衝區。begin()/end() 回傳非 const 迭代器也會觸發相同行為。呼叫任何可能導致重新配置的非 const 成員函式(如 push_back、reserve、clear),會使既有參考/迭代器失效,標準庫便可重新啟用 COW:
string base(10*1024*1024, 'x');
char c = base[0]; // COW 失效
base.push_back('y'); // 觸發重新配置,舊參考失效
// 之後複製又恢復高速
for (int i=0; i<100; ++i) { string copy = base; }
at() 或 c_str()/data(),避免非 const operator[]。base.cbegin()/base.cend() 取得 const 迭代器。COW 是把雙面刃:讀取操作若產生非 const 參考,即視為「潛在寫入」而失效共享。理解此語意邊界,能避免無意中將 O(1) 複製變成 O(N) 深拷貝。