系統程式設計師的 C++

值語意(value semantics)

當你把一份文件影印後把副本交給別人,你對原件的修改不會改到他的副本,他的修改也不會改到你的——兩者從此各自獨立。這就是值語意:變數持有自己的值,賦值或傳遞它會製作一份獨立的副本。對照之下是參考或指標語意,那裡兩個名字指向同一個底層物件,所以透過其一的修改透過另一個也看得見(像是以參考共用同一份文件,而非影印它)。

在 C++ 裡,物件預設具有值語意。若你寫 Widget b = a;,你得到第二個獨立的 Widget——b 的資料從 a 複製而來,之後更改 b 不會動到 a。參考(Widget& r = a;)或指標(Widget* p = &a;)給你的恰好相反:r 與 *p 只是 a 的別名,透過它們修改就是修改 a。複製建構子、移動操作與那組特殊成員函式的整套機制,存在的目的正是為了定義「為你的型別製作這個值的獨立副本」是什麼意思。

為何重要:值語意讓程式碼遠遠更容易推理,因為沒有遠距離的詭異作用——以值接收引數的函式無法改動你的物件,兩個相異的值也不會互為別名。這也是為什麼 std::vector 與 std::string 在賦值時複製其內容。誠實的取捨在於成本:複製大物件是實實在在的工作,而這正是移動語意被發明出來要緩解的問題。C 程式設計師在以值傳遞 struct(完整複製)相對於傳遞它的指標(共用)時就會感受到這點——C++ 把這個選擇形式化並加以擴展。

std::vector<int> a{1,2,3}; auto b = a; b.push_back(4); // a 仍是 {1,2,3};b 是 {1,2,3,4}——彼此獨立的副本

賦值複製了值;若改用參考或指標,修改 b 就會改到 a。

值語意是預設的,但正確性並非自動的:若你的類別持有一個裸的擁有指標而你什麼都不做,編譯器的預設複製會複製那個指標(淺複製),於是兩個物件擁有同一塊記憶體並重複釋放它。正確地定義複製——或改用 RAII 成員——才能讓值語意真正安全。

又称
copy semanticsvalue types值型別