• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            幽幽
             
            posts - 51,  comments - 28,  trackbacks - 0

            再談異常――談C++與Object Pascal中的構造函數(shù)與異常

            作者:Nicrosoft(nicrosoft@sunistudio.com) 2001.9.15
            個人主頁:http://www.sunistudio.com/nicrosoft/
            東日文檔:http://www.sunistudio.com/asp/sunidoc.asp

              我們知道,類的構造函數(shù)是沒有返回值的,如果構造函數(shù)構造對象失敗,不可能依靠返回錯誤代碼。那么,在程序中如何標識構造函數(shù)的失敗呢?最“標準”的方法就是:拋出一個異常。

              構造函數(shù)失敗,意味著對象的構造失敗,那么拋出異常之后,這個“半死不活”的對象會被如何處理呢?這就是本文的主題。

            在C++中,構造函數(shù)拋出異常后,析構函數(shù)不會被調用。這是合理的,因為此時對象并沒有被完整構造。也就是說,如果構造函數(shù)已經(jīng)做了一些諸如分配內存、 打開文件等操作的話,那么類需要有自己的成員來記住做過哪些動作。在C++中,經(jīng)典的解決方案是使用STL的標準類auto_ptr,這在每一本經(jīng)典 C++著作中都有介紹,我在這里就不多說了。在這里,我想再介紹一種“非常規(guī)”的方式,其思想就是避免在構造函數(shù)中拋出異常。我們可以在類中增加一個 Init(); 以及 UnInit();成員函數(shù)用于進行容易產(chǎn)生錯誤的資源分配工作,而真正的構造函數(shù)中先將所有成員置為NULL,然后調用 Init(); 并判斷其返回值(或者捕捉 Init()拋出的異常),如果Init();失敗了,則在構造函數(shù)中調用 UnInit(); 并設置一個標志位表明構造失敗。UnInit()中按照成員是否為NULL進行資源的釋放工作。示例代碼如下:
            class A
            {
            private:
             char* str;
             int failed;

            public:
             A();
             ~A();
             int Init();
             int UnInit();
             int Failed();
            };

            A::A()
            {
             str = NULL;
             try
             {
              Init();
              failed = 0;
             }
             catch(...)
             {
              failed = 1;
              UnInit();
             }
            }

            A::~A()
            {
             UnInit();
            }

            int A::Init()
            {
             str = new char[10];
             strcpy(str, "ABCDEFGHI");
             throw 10;

             return 1;
            }

            int A::UnInit()
            {
             if (!str)
             {
              delete []str;
              str = NULL;
             }

             printf("Free Resource

            ");
             return 1;
            }

            int A::Failed()
            {
             return failed;
            }

            int main(int argc, char* argv[])
            {
             A* a = new A;
             if ( a->Failed() )
              printf("failed

            ");
             else
              printf("succeeded

            ");

             delete a;

             getchar();
             return 0;
            }

              你會發(fā)現(xiàn),在int A::Init()中包含了throw 10;的代碼(產(chǎn)生一個異常,模擬錯誤的發(fā)生),執(zhí)行結果是:
              Free Resource
              failed
              Free Resource
              雖然 UnInit();被調用了兩次,但是由于UnInit();中做了判斷(if (!str)),因此不會發(fā)生錯誤。而如果沒有發(fā)生異常(去掉 int A::Init()中的throw 10;代碼),執(zhí)行結果是:
              Succeeded
              Free Resource
              和正常的流程沒有任何區(qū)別。

            在Object Pascal(Delphi/VCL)中,這個問題就變得非常的簡單了,因為 OP 對構造函數(shù)的異常的處理與C++不同,在Create時拋出異常后,編譯器會自動調用析構函數(shù)Destroy,并且會判斷哪些資源被分配了,實行自動回 收。因此,其代碼也變得非常簡潔,如下:
            type
              A = class
              private
              str : PChar;
              public
              constructor Create();
              destructor Destroy(); override;
              end;

            constructor A.Create();
            begin
              str := StrAlloc(10);
              StrCopy(str, 'ABCDEFGHI');
              raise Exception.Create('error');
            end;

            destructor A.Destroy();
            begin
              StrDispose(str);
              WriteLn('Free Resource');
            end;

            var oa : A;
              i : integer;
            begin
              try
                  oa := A.Create();
                  WriteLn('Succeeded');
                  oa.Free();
              except
                  oa := nil;
                  WriteLn('Failed');
              end;

              Read(i);
            end.

              在這段代碼中,如果構造函數(shù)拋出異常(即Create中含有raise Exception.Create('error');),執(zhí)行的結果是:
              Free Resource
              Failed
              此時的“Free Resource”輸出是由編譯器自動調用析構函數(shù)所產(chǎn)生的。而如果構造函數(shù)正常返回(即不拋出異常),則執(zhí)行結果是:
              Succeeded
              Free Resource
              此時的“Free Resource”輸出是由 oa.Free()的調用產(chǎn)生的。

            綜上,C++與Object Pascal對于構造函數(shù)拋出異常后的不同處理方式,其實正是兩種語言的設計思想的體現(xiàn)。C++秉承C的風格,注重效率,一切交給程序員來掌握,編譯器不 作多余動作。Object Pascal繼承Pascal的風格,注重程序的美學意義(不可否認,Pascal代碼是全世界最優(yōu)美的代碼),編譯器幫助程序員完成復雜的工作。兩種語 言都有存在的理由,都有存在的必要!而掌握它們之間的差別,能讓你更好地控制它們,達到自由的理想王國。


            posted on 2009-05-20 00:42 幽幽 閱讀(664) 評論(1)  編輯 收藏 引用 所屬分類: 雜集

            FeedBack:
            # re: 再談異常――談C++與Object Pascal中的構造函數(shù)與異常
            2009-05-20 09:56 | 陳梓瀚(vczh)
            C++更經(jīng)典的方案就是,在能夠拋出異常的構造函數(shù)里面,不要new指針,非要的話用智能指針……這樣固有的機制可以讓你連析構函數(shù)都不用寫。  回復  更多評論
              

            <2009年5月>
            262728293012
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456

            常用鏈接

            留言簿(6)

            隨筆分類(35)

            隨筆檔案(51)

            文章分類(3)

            文章檔案(3)

            相冊

            我的鏈接

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            亚洲午夜久久久| 青青青国产精品国产精品久久久久 | 久久天天躁狠狠躁夜夜avapp| 久久久久亚洲AV无码专区首JN| 久久影院综合精品| 91精品国产91久久| 国内精品综合久久久40p| 久久99国产精品久久99| 丁香色欲久久久久久综合网| 久久夜色精品国产亚洲| 亚洲午夜无码久久久久| 久久久久亚洲AV综合波多野结衣 | 久久久久亚洲av成人无码电影 | 久久久久一区二区三区| 久久久久久精品成人免费图片| 色综合久久精品中文字幕首页 | 亚洲综合久久综合激情久久| 色综合久久夜色精品国产| 人人狠狠综合久久亚洲88| 色综合久久无码中文字幕| 一级做a爰片久久毛片看看| 91久久九九无码成人网站 | 99精品久久久久久久婷婷| 久久激情五月丁香伊人| 久久九九有精品国产23百花影院| 久久超乳爆乳中文字幕| 婷婷久久久亚洲欧洲日产国码AV | 亚洲国产精品人久久| 久久久久亚洲AV片无码下载蜜桃| 久久狠狠爱亚洲综合影院| 久久综合精品国产一区二区三区| 久久久精品日本一区二区三区| www亚洲欲色成人久久精品| 国产精品久久久久无码av | 午夜精品久久久内射近拍高清| 91麻豆精品国产91久久久久久| 久久精品成人免费看| 99精品伊人久久久大香线蕉| 精品久久人人爽天天玩人人妻 | 婷婷综合久久中文字幕蜜桃三电影| 亚洲伊人久久精品影院|