當以同類別物件初始化新物件時呼叫:Test b = a;、函式傳值參數、函式回傳物件。若未自訂,編譯器產生預設拷貝建構函式 (逐成員複製)。
class Test {
public:
Test(int v) : val(v) {}
Test(const Test& other) : val(other.val) { // 自訂拷貝建構函式
cout << "拷貝建構函式被呼叫" << endl;
}
private:
int val;
};
參數必須為 const Test& (或 Test&),不可傳值 (否則無限遞迴)。
類別含指標成員指向動態記憶體時,預設逐成員複製僅複製指標值,雙物件指向同一記憶體。解構時雙重 delete 導致崩潰。
class Internet {
public:
Internet(char* n, char* a) {
strcpy(name, n); strcpy(addr, a);
cname = new char[strlen(n)+1];
strcpy(cname, n);
}
Internet(const Internet& other) { // 深拷貝
strcpy(name, other.name);
strcpy(addr, other.addr);
cname = new char[strlen(other.cname)+1]; // 重新配置記憶體
strcpy(cname, other.cname);
}
~Internet() { delete[] cname; }
private:
char name[20], addr[30];
char* cname; // 動態記憶體
};
核心:為指標成員配置新記憶體並複製內容,確保物件擁有獨立資源。
Internet Create() {
Internet temp("Lab", "lab.com");
return temp; // 產生臨時物件
}
void main() {
Internet a = Create(); // 呼叫拷貝建構函式初始化 a (可能被 RVO 優化)
}
編譯器可能執行 Return Value Optimization (RVO) 直接在呼叫端建構,省略臨時物件與拷貝。但語意上仍視為拷貝建構。
Internet a = Internet("Lab", "lab.com"); // 無名物件初始化
// 編譯器優化等同於:Internet a("Lab", "lab.com");
// 不會呼叫拷貝建構函式
C++ 標準允許編譯器省略無名物件的拷貝建構 (Copy Elision),直接建構目標物件。
const Internet& ref = Internet("Lab", "lab.com"); // 延長臨時物件壽命至參考結束
// 等價於:Internet temp("Lab", "lab.com"); const Internet& ref = temp;
非 const 左值參考無法綁定臨時物件 (C++11 起可用右值參考 Internet&&)。
std::string, std::vector, std::unique_ptr) 避免手動資源管理。