析構函數是類的一個成員函數,用於釋放類的對象在生存期程序為其分配的內存資源。由於析構函數是由程序自動調用的,那么我們就需要正確的分析出析構函數何時被調用。以下是我在學習過程中遇到的幾種易產生誤區的調用場景:
場景1> 對於一個全局函數,如果函數的形參的數據類型是類的對象,那么在函數作用域結束時,會自動調用析構函數,將形參的內存資源析構掉。同時,全局函數內部定義了一個臨時對象tmp,在執行return語句時,程序將調用拷貝構造函數,把臨時對象tmp拷貝給一個副本,稱副本為匿名對象。故最終return出來的對象是匿名對象而非臨時對象tmp。而tmp會被析構。因此,這段代碼實際調用了兩次析構函數。代碼如下:
1 #include "iostream" 2 using namespace std; 3 4 class Test 5 { 6 public: 7 int a; 8 public: 9 Test(int a = 0) 10 { 11 this->a = a; 12 } 13 Test(const Test &obj) 14 { 15 a = obj.a; 16 } 17 ~Test() 18 { 19 cout<<"我是析構函數"<<endl; 20 } 21 }; 22 23 Test MyCopy(Test p) 24 { 25 Test tmp = p; 26 return tmp; //先析構形參p,再析構tmp 27 } 28 29 void main() 30 { 31 Test t1(2); 32 Test t2 = MyCopy(t1); 33 34 cout<<"hello..."<<endl; 35 system("pause"); 36 return ; 37 }
輸出結果為:
場景2> 另外,主函數中的32行,返回的匿名對象通過“=”號賦值給t2,此時由於采用的是初始化的方式,因此編譯器會直接將匿名對象的名稱更改為t2,即直接轉化為t2,不會調用析構函數。而下面一種情況則需要調用,請看代碼:
Test t2;
t2 = MyCopy(t1);
由於此時代碼采用的是賦值的方式,因此編譯器會調用拷貝構造函數將匿名對象拷貝給t2,同時匿名對象被析構。這樣,析構函數就被調用了三次,程序更改后輸出結果如下:
場景3> 當全局函數形參為引用時,不會調用析構函數。代碼如下:
Test MyCopy(Test &p) { Test tmp = p; return tmp; } void main() { Test t1(2); Test t2 = MyCopy(t1); cout<<"hello..."<<endl; system("pause"); return ; }
由於引用的作用相當於指針,因此傳遞的只是對象所在的內存空間地址。又函數返回時采用初始化的方式,因此析構函數僅被執行一次。輸出結果如下: