析構函數調用時機的易錯點


析構函數是類的一個成員函數,用於釋放類的對象在生存期程序為其分配的內存資源。由於析構函數是由程序自動調用的,那么我們就需要正確的分析出析構函數何時被調用。以下是我在學習過程中遇到的幾種易產生誤區的調用場景:

場景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 ;
}

由於引用的作用相當於指針,因此傳遞的只是對象所在的內存空間地址。又函數返回時采用初始化的方式,因此析構函數僅被執行一次。輸出結果如下:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM