国产丰满大乳无码免费播放_久草一级毛片_国产av黄色一区二区_亚洲一级 片内射欧美乱强上司_制服丝袜亚洲日韩中文字幕欧美_亚洲av中文小島_国产精品无码久久av嫩草下载_91视频黄片软件APP大全

XML|HTML|TXT
您當(dāng)前位置: 軟件開發(fā)>> 新利在線娛樂>> 軟件開發(fā)技術(shù)>> 瀏覽文章

關(guān)于構(gòu)造函數(shù)和異常的分析

如果構(gòu)造函數(shù)內(nèi)發(fā)生異常,已經(jīng)分配的資源是不會(huì)自動(dò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;

}

運(yùn)行結(jié)果如下:

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

對(duì)象c在構(gòu)造過程中拋出異常,指針b指向的內(nèi)存空間不會(huì)被釋放。

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

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;

}

運(yùn)行結(jié)果如下:

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被正常釋放了,我們?cè)僮鲆幌赂淖儯瑢和c的構(gòu)造放到初始化列表中做,將D的構(gòu)造函數(shù)改成下面這樣,

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

{

}

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

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: ***

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

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

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

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

D() try:A(), b(new B(static_cast(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)析構(gòu)了,b的數(shù)據(jù)成員A已經(jīng)不存在,這是很危險(xiǎn)的。

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

try{

D d;

}catch (std::runtime_error &e){

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

}

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

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

1. 構(gòu)造函數(shù)體外的try-catch語句只有一個(gè)用途——轉(zhuǎn)換捕捉到的異常對(duì)象

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

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

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

class D{

auto_ptr b;

auto_ptr c;

}

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

{

}


手機(jī):18678812288 E-Mail:1069706080@qq.com
地址:山東省濟(jì)南市舜耕路泉城公園東門園內(nèi)向北50米 魯ICP備07011972號(hào) 版權(quán)所有2008-2013 新利體育18
Baidu