何時調用構造函數和析構函數


 

來源網址:http://blog.csdn.net/feitianxuxue/article/details/7323054

來源博客:feitianxuxue的專欄

何時調用構造函數和析構函數

構造函數的作用是保證每個對象的數據成員都有何時的初始值。

析構函數的作用是回收內存和資源,通常用於釋放在構造函數或對象生命期內獲取的資源。

一般我們都知道構造和析構的次序:

    構造從類層次的最根處開始,在每一層中,首先調用基類的構造函數,然后調用成員對象的構造函數。析構則嚴格按照與構造相反的次序執行,該次序是唯一的,否則編譯器將無法自動執行析構過程。

    構造函數和析構函數都是由編譯器隱式調用的。這些函數的調用順序取決於程序的執行進入和離開實例化對象時所在的那個作用域的順序。一般而言,析構函數的調用順序和構造函數的調用順序相反,但是,對象的存儲類可以改變析構函數的調用順序。

    對於在全局作用域中定義的對象,它們的構造函數是在文件中所有其他函數(包括main)開始執行之前被調用的(但無法保證不同文件的全局對象構造函數的執行順序)。對應的析構函數是在終止main之后調用的。

    exit函數會迫使程序立即終止,而不會執行自動對象的析構函數。這個函數經常用來在檢測到輸入錯誤或者程序所處理的文件無法打開時終止程序。

    abort函數與exit函數功能相似,但它會迫使程序立即終止,而不允許調用任何對象的析構函數。abort函數通常用來表明程序的非正常終止。

    自動局部變量的構造函數是在程序的執行到達定義這個對象的位置時調用的,而對應的析構函數是在程序離開這個對象的作用域時調用的(即定義這個對象的代碼完成了執行)。每次執行進入和離開自動對象的作用域時,都會調用它的構造函數和析構函數。如果程序調用了exit或abort函數而終止,則不會調用自動對象的析構函數。

    靜態局部對象的析構函數只調用一次,即執行首次到達定義這個對象的位置時。對應的析構函數是在main終止或程序調用exit函數時調用的。

    全局對象和靜態對象是以創建它們時相反的順序銷毀的。如果程序由於調用了exit函數而終止,則不會調用靜態對象的析構函數。

下面的demo演示了在幾個作用域不同的存儲類的CreateAndDestory的類的對象,它們的構造函數和析構函數的調用順序。

[cpp]  view plain  copy
 
  1. #include <iostream>  
  2. #include <string>  
  3. using namespace std;  
  4.   
  5. class Demo  
  6. {  
  7. public:  
  8.  Demo(int,string);  //構造函數  
  9.  ~Demo();          //析構函數  
  10. private:  
  11.  int objectID;    //ID number for object  
  12.  string message;   //message describing object  
  13. };  
  14.   
  15. Demo::Demo(int ID,string messagestring)  
  16. {  
  17.  objectID = ID;   //set object's ID number  
  18.  message = messagestring;  //set object's descriptive message  
  19.   
  20.  cout<<"Object "<<objectID<<" constructor runs  "<<message<<endl;  
  21. }  
  22.   
  23. Demo::~Demo()  
  24. {  
  25.  cout<<(objectID==1 || objectID==6 ? "\n" : "");  
  26.   
  27.  cout<<"Object "<<objectID <<" destructor runs  "<<message<<endl;  
  28. }  
  29.   
  30. void create(void);  
  31.   
  32. Demo first(1,"(main 前的全局對象)");   //在全局作用域下定義first對象。它的構造函數是在執行main中的任何語句之前調用的  
  33.                                        //而它的析構函數是在已經運行了所有其他對象的析構函數之后,程序終止時調用  
  34.    
  35. int _tmain(int argc, _TCHAR* argv[])  
  36. {  
  37.  cout<<"\n main 函數開始執行:"<<endl;  
  38.  Demo second(2,"(main 函數中的局部自動對象)");  
  39.  static Demo third(3,"(main 函數中的靜態局部對象)");  
  40.   
  41.  create();  
  42.   
  43.  cout<<"\n main 函數:繼續執行"<<endl;  
  44.  Demo fourth(4,"(main 函數中的局部自動對象)");  
  45.  cout<<"\n main 函數:執行結束"<<endl;  
  46.  system("pause");  
  47.  return 0;  
  48. }  
  49.   
  50. void create(void)  
  51. {  
  52.  cout<<"\n create 函數:開始執行"<<endl;  
  53.  Demo fifth(5,"(cerate 函數里的本地自動對象)");  
  54.  static Demo sixth(6,"(cerate 函數里的本地靜態對象)");  
  55.  Demo seventh(7,"(cerate 函數里的本地自動對象)");  
  56.  cout<<"\ncerate 函數:執行結束"<<endl;  
  57. }  


運行結果:

 

Object 6 destructor runs (cerate 函數里的本地靜態對象)

Object 3 destructor runs (main函數中的本地靜態對象)

Object 1 destructor runs (main函數前的全局對象)

分析:

    Main函數中聲明了3個對象,second對象,fourth對象,是局部自動對象,而third對象是一個靜態局部對象。當執行到達對象的聲明位置時,才會調用這些對象的構造函數。

當執行到達mian的末尾時,首先調用fourth對象的析構函數,然后是second對象的析構函數。由於third對象是靜態的,因此它會存活到程序終止。調用third對象的析構函數的時機,是在調用全局對象first的析構函數之前,但在所有其他對象被銷毀之后。

    Create函數聲明了3個對象,其中fifth和seventh是局部自動對象,sixth是靜態局部對象。當create終止時,首先調用seventh對象的析構函數,然后是fifth對象的析構函數。由於sixth對象是靜態的,因此它會存活到程序終止。調用sixth對象的析構函數的時機,是在調用third和first的析構函數之前,但在所有其他對象被銷毀之后。

參考資料:《c++程序員教程》 電子工業出版社 張良華 譯 P259-262

 
3


免責聲明!

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



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