C++對象的構造、賦值和析構

          Posted on 2006-11-25 16:08 iceboundrock 閱讀(636) 評論(1)  編輯  收藏 所屬分類: 算法與數據結構學習

          C++ C#/java 有很多區別,其中最大的區別當數對內存的管理。

          C++ 中,類的使用者決定了類的實例內存會如何分配,分配在堆上還是棧上。我們先看一段例子程序:

          ?

          #include "stdio.h"

          ?

          class Demo{

          public :

          ??? int i;

          ??? char* objName;

          ??? Demo(){

          ??????? objName = "Default object.";

          ??????? printf("%s, objName = %s\r\n", "Enter Demo default ctor. method.", objName);

          ???????

          ??????? i = 1000;

          ??? }

          ?

          ??? Demo(int ival, char* name){

          ??????? printf("%s,i = %d, objName = %s\r\n", "Enter Demo(int ival) ctor method", ival, name);

          ??????? i = ival;

          ??????? objName = name;

          ??? }

          ?

          ??? Demo(const Demo& d){

          ??????? printf("%s\r\n", "Enter Demo copy ctor method.");

          ??????? i = d.i;

          ??????? objName = "copied d";

          ??? }

          ?

          ??? ~Demo(){

          ??????? printf("%s, i = %d, objName = %s\r\n", "Enter Demo dector. method" , i, objName);

          ??? }

          };

          ?

          Demo& testMethod0(){

          ??? printf("%s\r\n", "Enter testMethod0.");

          ??? Demo d(0, "d in testMethod0");

          ??? printf("%s\r\n", "Exit testMethod0.");

          ??? return d;

          }

          ?

          Demo testMethod1(){

          ??? printf("%s\r\n", "Enter testMethod1.");

          ??? Demo d(1, "d in testMethod1");

          ??? printf("%s\r\n", "Exit testMethod1.");

          ??? return d;

          }

          ?

          Demo* testMethod2(){

          ??? printf("%s\r\n", "Enter testMethod2.");

          ??? Demo *d = new Demo(2, "d in testMethod2");

          ??? printf("%s\r\n", "Exit testMethod2.");

          ??? return d;

          }

          ?

          int main(int argc, _TCHAR* argv[])

          {

          ??? Demo d;

          ??? d = testMethod1();

          ?

          ??? Demo& d1 = testMethod0();

          ?

          ??? Demo d2(999, "d1");

          ?

          ??? Demo* d3 = testMethod2();

          ?

          ??? printf("d.i = %d\r\n", d.i);

          ??? printf("d1.i = %d\r\n", d1.i);

          ??? printf("d2.i = %d\r\n", d2.i);

          ??? printf("d3.i = %d\r\n", d3->i);

          ?

          ??? delete d3;

          ??? return 0;

          }

          ?

          Output

          Enter Demo default ctor. method., objName = Default object.

          Enter testMethod1.

          Enter Demo(int ival) ctor method,i = 1, objName = d in testMethod1

          Exit testMethod1.

          Enter Demo copy ctor method.

          Enter Demo dector. method, i = 1, objName = d in testMethod1

          Enter Demo dector. method, i = 1, objName = copied d

          Enter testMethod0.

          Enter Demo(int ival) ctor method,i = 0, objName = d in testMethod0

          Exit testMethod0.

          Enter Demo dector. method, i = 0, objName = d in testMethod0

          Enter Demo(int ival) ctor method,i = 999, objName = d1

          Enter testMethod2

          Enter Demo(int ival) ctor method,i = 2, objName = d in testMethod2

          Exit testMethod2.

          d.i = 1

          d1.i = -2

          d2.i = 999

          d3.i = 2

          Enter Demo dector. method, i = 2, objName = d in testMethod2

          Enter Demo dector. method, i = 999, objName = d1

          Enter Demo dector. method, i = 1, objName = copied d

          ?

          C# 不同,在 C++ 中,對象聲明的時候就已經執行了構造函數,比如上面例子的 main 函數中的第一行, Demo d ,從屏幕上的輸出來看,這個時候 Demo class 的默認構造函數會被調用。

          接下來的一行代碼調用,引出了很有趣的情況,當然也隱藏著不小的問題。這行代碼造成了一次構造函數調用,一次拷貝構造函數調用和兩次析構函數調用。讓我們來具體分析一下:第一次調用構造函數很容易理解,因為在 testMethod1 中我們聲明了 Demo d(0) ,退出 testMethod1 ,函數的返回值要賦值給變量 d2 ,這個時候, d2 被拷貝構造函數重新構造了一次。接著 testMethod1 中構造的局部變量被析構,然后,居然拷貝構造函數構造的對象也被析構?等等,看完所有輸出,我們發現, objName = copied d 的對象被析構兩次,而 objName = Default obj 的對象被構造出之后沒有被析構,這里隱藏了很嚴重的問題,有可能導致內存泄漏、句柄不能被正確關閉等等。另外,拷貝構造函數的執行可能導致潛在的效率問題,考慮一個包含巨大矩陣的對象, copy 這個對象會怎么樣?

          ?

          接下來的一行代碼, testMethod0 返回一個對象的引用,當然不會導致拷貝構造函數被調用,但是,這樣也是有問題的,在函數中聲明的局部變量在函數執行完成的時候會被析構,那么直接返回局部變量就可能會出現問題。 testMethod0 退出以后,他內部的 Demo 對象就會自動析構,外面對它的引用當然也無法指向正確的對象了,所以后面程序打印 d.i 的時候,輸出了一個莫名其妙的 -2

          ?

          效率最好的方法當數返回指針了,它不會導致對象復制,如果使用得當,也不會導致內存泄漏或者句柄泄漏。 testMethod2 演示了這種情況,當然,你需要手工刪除在 testMethod2 中創建的對象。

          ?

          ?

          Feedback

          # re: C++對象的構造、賦值和析構  回復  更多評論   

          2006-11-28 09:50 by iceboundrock
          補充一點關于數組的內容,
          如果在C++中聲明一個對象的數組,不像C#,數組中默認的元素都是null,C++的數組中可以容納多少元素就會在聲明數組的時候執行多少次構造函數將實際函數構造出來。

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          posts - 10, comments - 15, trackbacks - 0, articles - 0

          Copyright © iceboundrock

          主站蜘蛛池模板: 湄潭县| 灵武市| 新河县| 酒泉市| 怀化市| 西和县| 成安县| 静海县| 当雄县| 岱山县| 新干县| 天气| 南郑县| 南丰县| 塔城市| 金坛市| 顺平县| 文昌市| 中卫市| 慈溪市| 曲靖市| 辽阳市| 资溪县| 阳山县| 达尔| 锡林郭勒盟| 承德县| 洞头县| 黑河市| 恩施市| 乐昌市| 中方县| 邛崃市| 洛南县| 富顺县| 石门县| 厦门市| 子长县| 田东县| 陈巴尔虎旗| 武邑县|