• <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中的構(gòu)造函數(shù)與異常

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

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

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

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

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

            在Object Pascal(Delphi/VCL)中,這個(gè)問題就變得非常的簡(jiǎn)單了,因?yàn)?OP 對(duì)構(gòu)造函數(shù)的異常的處理與C++不同,在Create時(shí)拋出異常后,編譯器會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)Destroy,并且會(huì)判斷哪些資源被分配了,實(shí)行自動(dòng)回 收。因此,其代碼也變得非常簡(jiǎn)潔,如下:
            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.

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

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


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

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

            <2010年10月>
            262728293012
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456

            常用鏈接

            留言簿(6)

            隨筆分類(35)

            隨筆檔案(51)

            文章分類(3)

            文章檔案(3)

            相冊(cè)

            我的鏈接

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            久久久久综合国产欧美一区二区 | 亚洲欧美国产日韩综合久久| 亚洲中文久久精品无码ww16 | 久久精品国产第一区二区| 久久久久亚洲AV无码永不| 国产成人无码精品久久久性色| 久久久无码精品午夜| 久久一区二区三区免费| 久久婷婷五月综合97色直播| 欧美色综合久久久久久| 久久亚洲视频| 国内精品伊人久久久久777| 伊人色综合久久天天人手人婷| 亚洲国产精品一区二区久久hs| 狠狠色狠狠色综合久久| www性久久久com| 国产精品欧美久久久久无广告 | 婷婷伊人久久大香线蕉AV| 欧美午夜精品久久久久免费视 | 国产精品久久久久国产A级| 国产∨亚洲V天堂无码久久久| 一本久久a久久精品综合夜夜| 国产成人精品久久亚洲高清不卡| 精品多毛少妇人妻AV免费久久| 久久夜色精品国产www| 综合人妻久久一区二区精品| 精品久久久久久久久午夜福利 | 九九热久久免费视频| 综合久久一区二区三区 | 日韩久久久久中文字幕人妻| 日韩精品久久久久久久电影| 久久亚洲欧美国产精品| 欧美日韩中文字幕久久伊人| 亚洲中文字幕伊人久久无码| 久久99久久99精品免视看动漫| 国产伊人久久| 久久精品无码专区免费东京热| 国产高潮国产高潮久久久91 | 精品无码久久久久久国产| 日韩精品久久久久久久电影蜜臀| 99久久99久久精品国产|