在 VC++2005 中編譯執行以下代碼:
#include <iostream>
using namespace std;
struct A {
A() { cout << "A()" << endl; }
// A(const A&) { cout << "A(A)" << endl; }
A& operator=(const A&) { cout << "A=A" << endl; }
~A() { cout << "~A()" << endl; }
};
A foo(A a) {
cout << "---" << endl;
return a;
}
int main() {
{
foo(A());
}
system("pause");
return 0;
}
輸出結果為:
A()
---
~A()
~A()
~A()
問題在於:return a; 為什麼會觸發兩次析構函數調用?
將函數返回類型改為 void,觀察行為差異:
void foo(A a) { }
int main() {
{
foo(A());
}
system("pause");
return 0;
}
輸出:
A()
~A()
~A()
取消註釋 A(const A&) { cout << "A(A)" << endl; }
輸出:
A()
~A()
A() 創建一個臨時對象,作為實參傳遞給 foo(A a)。由於參數是按值傳遞,編譯器需要構造參數 a。
foo(A()) 時:先構造臨時對象(輸出 A()),再用合成的拷貝構造函數構造參數 a(無輸出)。a(第一次 ~A())。~A())。return a;,還會構造返回值臨時對象(再次拷貝),並在 main 中銷毀它(第三次 ~A())。A(A))。A())和一次析構(~A())。VC++2005 的優化策略受「是否存在用戶定義拷貝構造函數」影響:
這屬於編譯器實現細節,現代 C++(C++17 起)強制要求複製省略,行為更加一致。