當類別未自訂拷貝建構函數時,編譯器自動產生「逐成員拷貝」版本:
class Test {
public:
Test(int v) : p1(v) {}
int p1;
};
Test a(99);
Test b = a; // 呼叫編譯器產生的淺拷貝建構函數
對於 int 等值型別成員,淺拷貝無問題。但若成員為**指標/資源控制代碼**,淺拷貝會導致雙重釋放、記憶體洩漏、資料競爭。
class DeepCopy {
char* buffer;
size_t len;
public:
DeepCopy(const char* s) : len(strlen(s)) {
buffer = new char[len + 1];
strcpy(buffer, s);
}
// 自訂拷貝建構函數:分配新記憶體並複製內容
DeepCopy(const DeepCopy& other) : len(other.len) {
buffer = new char[len + 1];
strcpy(buffer, other.buffer);
}
~DeepCopy() { delete[] buffer; }
// 拷貝指派運算子同理需自訂 (Rule of Three)
DeepCopy& operator=(const DeepCopy& other) {
if (this != &other) {
delete[] buffer;
len = other.len;
buffer = new char[len + 1];
strcpy(buffer, other.buffer);
}
return *this;
}
};
新增移動建構函數與移動指派運算子,避免不必要的深拷貝:
DeepCopy(DeepCopy&& other) noexcept : buffer(other.buffer), len(other.len) {
other.buffer = nullptr;
other.len = 0;
}
DeepCopy& operator=(DeepCopy&& other) noexcept {
if (this != &other) {
delete[] buffer;
buffer = other.buffer;
len = other.len;
other.buffer = nullptr;
other.len = 0;
}
return *this;
}
| 場景 | 策略 |
|---|---|
| 無動態資源成員 (純值型別) | 使用預設拷貝/指派 (Rule of Zero) |
| 擁有獨佔資源 (指標、檔案控制代碼、socket) | 自訂深拷貝 + 移動語意 (Rule of Five),或使用 std::unique_ptr/std::string/std::vector 讓編譯器自動正確生成 (Rule of Zero) |
| 共享資源 (參考計數) | 使用 std::shared_ptr,預設拷貝即正確 |
「誰分配,誰釋放;拷貝即複製資源,移動即轉移所有權。善用標準庫容器與智慧型指標,讓編譯器幫你守規矩。」