T t2 = t1;)。此時編譯器執行位元拷貝 (bitwise copy),不會呼叫建構函式,導致資源管理型別 (含指標、檔案控制代碼、鎖) 出現雙重釋放、淺層複製等嚴重錯誤。
class CTest {
public:
CTest() { cout << "construct\n"; }
~CTest() { cout << "destruct\n"; }
};
void test(CTest obj) {} // 傳值參數
int main() {
CTest obj;
test(obj); // 輸出: construct, destruct, destruct
// 僅呼叫 1 次建構、2 次解構!臨時物件未正確初始化
}
class CTest {
public:
int* data;
CTest() : data(new int(0)) { cout << "construct\n"; }
CTest(const CTest& other) : data(new int(*other.data)) { // 深層複製
cout << "copy construct\n";
}
~CTest() { delete data; cout << "destruct\n"; }
};
// 輸出: construct, copy construct, destruct, destruct
T t1, t2; t2 = t1; 不呼叫拷貝建構函式 (t2 已初始化),需重載 operator=:
CTest& operator=(const CTest& other) {
if (this != &other) { // 自我指派檢查
delete data; // 釋放舊資源
data = new int(*other.data); // 深層複製
}
return *this; // 支援鏈式指派
}
| 函式 | C++98 | C++11+ |
|---|---|---|
| 解構函式 | 必要 | 必要 |
| 拷貝建構 | 必要 | 必要 |
| 拷貝指派 | 必要 | 必要 |
| 移動建構 | — | 必要 (資源竊取) |
| 移動指派 | — | 必要 |
std::vector, std::unique_ptr) 讓編譯器自動生成正確的五大函式 (Rule of Zero)。operator= 必做:自我指派檢查、釋放舊資源、深層複製、回傳 *this。const T&,避免無限遞迴。noexcept 標記移動操作,啟用容器優化 (如 vector::resize 選用移動而非拷貝)。雖然編譯器會合成預設拷貝/指派,但僅執行淺層逐成員拷貝。對管理動態資源的類別,預設行為幾乎必定錯誤。寧可顯式刪除 (=delete) 禁用拷貝,也不可依賴預設行為。