九九热这里直有精品,1区二区三区在线播放,玖玖爱在线观看资源,国产aⅴ综合网,午夜福利男女,日本亚洲欧美三级,日韩无码黄色导航,内射少妇13区,中文字幕高清网

您身邊的軟件定制專家--9年開發(fā)經(jīng)驗為您護航

18678812288
0531-88887250

關于構造函數(shù)和異常的分析

文章作者:濟南軟件開發(fā) 時間:2016年12月20日

如果構造函數(shù)內發(fā)生異常,已經(jīng)分配的資源是不會自動釋放的,比如

 

 

class B{

public:

    B(){

        printf("into B constructor\n");

    }    

    ~B(){

        printf("into B destructor\n");

    }

};

 

class C{

public:

    C(){

        printf("into C constructor\n");

        throw std::runtime_error(" exception from C constructor");

    }    

    ~C(){

        printf("into C destructor\n");

        }

};

class A{

public:

    A(){

        printf("into A constructor \n");

    }

    ~A(){

        printf("into A destructor \n");

    }

};

 

class D:A{

public:

    D():A(), b(NULL),c(NULL) {

        printf("into D constructor\n");

        b = new B();

        c = new C();

    }

    ~D(){

        printf("into D destructor\n");

        delete b;

        delete c;

    }

private:

    B *b;

    C *c;

};

 

int main(int argc, char **argv){

    D d;

    return 0;

}

 

運行結果如下:

 

into A constructor

 

into D constructor

 

into B constructor

 

into C constructor

 

terminate called after throwing an instance of 'std::runtime_error'

 

what(): exception from C constructor

 

對象c在構造過程中拋出異常,指針b指向的內存空間不會被釋放。

 

如何釋放b的內存呢?首先我們可以看出c++是不會調用析構函數(shù)的,因為析構函數(shù)不知道對象已經(jīng)構造了多少,哪些資源該釋放,哪些不該釋放,當然編譯器可以記錄這些內容,但是會嚴重影響效率。另外在語義上,c++認為,對象的生命周期是構造函數(shù)正常結束至析構函數(shù)結束之間,構造不完全的對象是一個沒有生命的東西,是不存在的,你不能對一個不存在的對象調用析構函數(shù)。編譯器默認會做的只是釋放對象d的內存空間。對象b指向的堆內存可以通過使用異常顯示釋放

 

 

D():A(), b(NULL), c(NULL){

        printf("into D constructor\n");

        try{

            b = new B();

            c = new C();

        }catch(std::runtime_error &e){

            printf("into D constructor catch \n");

            delete b; b=NULL;

            delete c; c=NULL;

       }

 

運行結果如下:

 

into A constructor

 

into D constructor

 

into B constructor

 

into C constructor

 

into D constructor catch

 

into B destructor

 

into D destructor

 

into A destructor

 

b被正常釋放了,我們再做一下改變,將b和c的構造放到初始化列表中做,將D的構造函數(shù)改成下面這樣,

 

D::D() : A(),b(new B()),c(new C())

   {

   }

我們繼續(xù)使用異常,會不會有效?

 

D() try:A(), b(new B()), c(new C()) {

        printf("into D constructor\n");

}catch(std::runtime_error &e){

        printf("in D constructor catch: %s \n", e.what());

        cleanup();

}

看上去very nice啊,跑一下試試,

 

into A constructor

 

into B constructor

 

into C constructor

 

into A destructor

 

in D constructor catch: exception from C constructor

 

into B destructor

 

into C destructor

 

*** glibc detected *** ./a.out: free(): invalid pointer: ***

 

指針錯誤!同時我們可以發(fā)現(xiàn)在進入catch語句前基類A執(zhí)行了析構函數(shù),這說明到達catch語句時,已經(jīng)跳出了構造函數(shù)的范圍,D和A的成員數(shù)據(jù)都已經(jīng)是不可訪問的了。

 

C++為什么要這樣做呢,為什么構造函數(shù)體外的catch語句中無法訪問數(shù)據(jù)成員?

 

首先,無法知道b和c是否已經(jīng)初始化了,刪除未初始化指針是非法的。

 

其次,我們假設可以知道b初始化了,c沒有初始化,我們要刪除b,如果catch中可以訪問b和c的話(我們做個假設),改變B的類型,使B包含一個A*成員數(shù)據(jù),考慮下這種情況,

 

D() try:A(), b(new B(static_cast<A*>(this))), c(new C()) {

         printf("into D constructor\n");

}catch(std::runtime_error &e){

         printf("in D constructor catch: %s \n", e.what());

         cleanup();

}

A已經(jīng)析構了,b的數(shù)據(jù)成員A已經(jīng)不存在,這是很危險的。

 

c++認為,不管是基類還是數(shù)據(jù)成員構造出現(xiàn)失敗,那么整個對象構造都是失敗的,不存在半成品。構造函數(shù)塊外的catch語句(上面這種)即使沒有顯示地重新拋出異常,c++也會自動拋出,一直到最下層派生類對象構造處停住。比如以上例子,catch沒有顯示throw,在main函數(shù)里:

 

try{    

        D d;

}catch (std::runtime_error &e){

        printf("int main: %s\n", e.what());

}

仍然會捕捉到C構造函數(shù)拋出的runtime_error異常。

 

綜上,可以總結以下規(guī)則

 

1. 構造函數(shù)體外的try-catch語句只有一個用途——轉換捕捉到的異常對象

 

2. 必須在構造函數(shù)體內分配資源,不要在初始化列表中

 

3. 一定要用try-catch語句管理資源的話,在構造函數(shù)體內。

 

4. 使用RAII方式管理資源,這會少死亡很多腦細胞,像這樣子

 

 

class D{

    auto_ptr<B> b;

    auto_ptr<C> c;

}

D::D() : A( ),b(new B()), c(new C())

{

}


想要了解更多詳情歡迎來電咨詢18678812288
登陸網(wǎng)址:m.h6244.cn。
聯(lián)系人:王經(jīng)理。

德阳市| 宽甸| 淄博市| 青海省| 兖州市| 杭锦旗| 沧州市| 新宾| 屯昌县| 宜兴市| 泰州市| 府谷县| 信阳市| 壶关县| 垦利县| 阜新| 绥棱县| 开平市| 绥德县| 黑龙江省| 花莲市| 比如县| 宣武区| 深州市| 武川县| 班戈县| 驻马店市| 都昌县| 香港| 太仆寺旗| 晋中市| 南江县| 修水县| 宣汉县| 永济市| 弋阳县| 肇源县| 孟津县| 沂源县| 股票| 灌阳县|