第7集構(gòu)造函數(shù)中拋出的異常

字號:

上一篇文章簡單討論了一下對象的成員函數(shù)拋出異常時的處理情況。本文中將繼續(xù)討論當(dāng)在構(gòu)造函數(shù)中拋出異常時,程序的執(zhí)行情況又如何?這有點復(fù)雜呀!而且主人公阿愚還覺得這蠻有點意思!
    構(gòu)造函數(shù)中拋出的異常
    1、標(biāo)準(zhǔn)C++中定義構(gòu)造函數(shù)是一個對象構(gòu)建自己,分配所需資源的地方,一旦構(gòu)造函數(shù)執(zhí)行完畢,則表明這個對象已經(jīng)誕生了,有自己的行為和內(nèi)部的運行狀態(tài),之后還有對象的消亡過程(析構(gòu)函數(shù)的執(zhí)行)??烧l能保證對象的構(gòu)造過程一定能成功呢?說不定系統(tǒng)當(dāng)前的某個資源不夠,導(dǎo)致對象不能完全構(gòu)建好自己(人都有畸形兒,更何況別的呢?朋友們!是吧!),因此通過什么方法來表明對象的構(gòu)造失敗了呢?C++程序員朋友們知道,C++中的構(gòu)造函數(shù)是沒有返回值的,所以不少關(guān)于C++編程方面的書上得出結(jié)論:“因為構(gòu)造函數(shù)沒有返回值,所以通知對象的構(gòu)造失敗的方法那就是在構(gòu)造函數(shù)中拋出異常”。主人公阿愚非常不同意這種說法,誰說的,便不信邪!雖然C++標(biāo)準(zhǔn)規(guī)定構(gòu)造函數(shù)是沒有返回值,可我們知道每個函數(shù)實際上都會有一個返回值的,這個值被保存在eax寄存器中,因此實際上是有辦法通過編程來實現(xiàn)構(gòu)造函數(shù)返回一個值給上層的對象創(chuàng)建者。當(dāng)然即便是構(gòu)造函數(shù)真的不能有返回值,我們也可以通過一個指針類型或引用類型的出參來獲知對象的構(gòu)造過程的狀態(tài)。示例如下:
    class MyTest_Base
    {
    public:
    MyTest_Base (int& status)
    {
    //do other job
    // 由于資源不夠,對象構(gòu)建失敗
    // 把status置0,通知對象的構(gòu)建者
    status = 0;
    }
    protected:
    };
    void main()
    {
    int status;
    MyTest_Base obj1(status);
    // 檢查對象的構(gòu)建是否成功
    if(status ==0) cout << “對象構(gòu)建失敗” << endl;
    }
    程序運行的結(jié)果是:
    對象構(gòu)建失敗
    是?。∩厦嫖覀儾灰驳玫搅藢ο髽?gòu)造的成功與否的信息了嗎?可大家有沒有覺得這當(dāng)中有點問題?主人公阿愚建議大家在此停留片刻,仔細(xì)想想它會有什么問題?OK!也許大家都知道了問題的所在,來驗證一下吧!
    class MyTest_Base
    {
    public:
    MyTest_Base (int& status)
    {
    //do other job
    // 由于資源不夠,對象構(gòu)建失敗
    // 把status置0,通知對象的構(gòu)建者
    status = 0;
    }
    virtual ~ MyTest_Base ()
    {
    cout << “銷毀一個MyTest_Base類型的對象” << endl;
    }
    protected:
    };
    void main()
    {
    int status;
    MyTest_Base obj1(status);
    // 檢查對象的構(gòu)建是否成功
    if(status ==0) cout << “對象構(gòu)建失敗” << endl;
    }
    程序運行的結(jié)果是:
    對象構(gòu)建失敗
    銷毀一個MyTest_Base類型的對象
    沒錯,對象的析構(gòu)函數(shù)被運行了,這與C++標(biāo)準(zhǔn)中所規(guī)定的面向?qū)ο蟮囊恍┨匦允怯袥_突的。一個對象都沒有完成自己的構(gòu)造,又何來析構(gòu)!好比一個夭折的畸形兒還沒有出生,又何來死之言。因此這種方法是行不通的。那怎么辦?那就是上面那個結(jié)論中的后一句話是對的,通知對象的構(gòu)造失敗的方法那就是在構(gòu)造函數(shù)中拋出異常,但原因卻不是由于構(gòu)造函數(shù)沒有返回值而造成的。恰恰相反,C++標(biāo)準(zhǔn)中規(guī)定構(gòu)造函數(shù)沒有返回值正是由于擔(dān)心很容易與面向?qū)ο蟮囊恍┨匦韵鄾_突,因此干脆來個規(guī)定,構(gòu)造函數(shù)不能有返回值(主人公阿愚的個人理解,有不同意見的朋友歡迎討論)。
     2、構(gòu)造函數(shù)中拋出異常將導(dǎo)致對象的析構(gòu)函數(shù)不被執(zhí)行。哈哈^-^,阿愚很開心,瞧瞧!如果沒有C++的異常處理機(jī)制鼎立支持,C++中的面向?qū)ο筇匦远紵o法真正實現(xiàn)起來,C++標(biāo)準(zhǔn)總不能規(guī)定所有的對象都必須成功構(gòu)造吧!這也太理想化了,也許只有等到共產(chǎn)主義社會實現(xiàn)的那一天(CPU可以隨便拿,內(nèi)存可以隨便拿,所有的資源都是你的?。┎耪f不定有可能·····,所以說C++的異常處理和面向?qū)ο蟠_實是誰也離不開誰。當(dāng)然示例還是要看一下,如下:
    class MyTest_Base
    {
    public:
    MyTest_Base (string name = “”) : m_name(name)
    {
    throw std::exception(“在構(gòu)造函數(shù)中拋出一個異常,測試!”);
    cout << “構(gòu)造一個MyTest_Base類型的對象,對象名為:”<    }
    virtual ~ MyTest_Base ()
    {
    cout << “銷毀一個MyTest_Base類型的對象,對象名為:”<    }
    void Func() throw()
    {
    throw std::exception(“故意拋出一個異常,測試!”);
    }
    void Other() {}
    protected:
    string m_name;
    };
    void main()
    {
    try
    {
    // 對象構(gòu)造時將會拋出異常
    MyTest_Base obj1(“obj1”);
    obj1.Func();
    obj1.Other();
    }
    catch(std::exception e)
    {
    cout << e.what() << endl;
    }
    catch(...)
    {
    cout << “unknow exception”<< endl;
    }
    }
    程序的運行結(jié)果將會驗證:“構(gòu)造函數(shù)中拋出異常將導(dǎo)致對象的析構(gòu)函數(shù)不被執(zhí)行”