构造函数失败_抛出异常
網(wǎng)上比較經(jīng)典的總結(jié):
什么函數(shù)都有可能失敗,構(gòu)造函數(shù)也不另外,比如new一個對象或空間不成功。當(dāng)構(gòu)造函數(shù)失敗的時候,其實很多時候我們不想這個對象被繼續(xù)生成,這個時候就可以在構(gòu)造函數(shù)里面拋出異常。C++規(guī)定構(gòu)造函數(shù)拋出異常之后,對象將不被創(chuàng)建,析構(gòu)函數(shù)也不會被執(zhí)行,但已經(jīng)創(chuàng)建成功的部分(比如一個類成員變量)會被部分逆序析構(gòu),不會產(chǎn)生內(nèi)存泄漏。但有些資源需要在拋出異常前自己清理掉,比如打開成功的一個文件,最好關(guān)閉掉再拋出異常(雖然系統(tǒng)也會把這個資源回收),因為拋出異常之后析構(gòu)函數(shù)不會被執(zhí)行了。
? ? ? (1) C++中通知對象構(gòu)造失敗的唯一方法那就是在構(gòu)造函數(shù)中拋出異常;(這句話并不是說我們只有這個方法才能讓上層知道構(gòu)造函數(shù)失敗,雖然構(gòu)造函數(shù)沒有返回值,我們完全可以在構(gòu)造函數(shù)中傳入一個引用值,然后在里面設(shè)置狀態(tài),運行完構(gòu)造函數(shù)之后任然可以知道是否失敗,但這種情況下面對象其實還是被構(gòu)造出來的,只是里面有資源分配失敗而已,并且析構(gòu)函數(shù)還是會執(zhí)行。這和我們構(gòu)造失敗不生成對象的初衷不符。)
(2) 構(gòu)造函數(shù)中拋出異常將導(dǎo)致對象的析構(gòu)函數(shù)不被執(zhí)行;(但已經(jīng)生產(chǎn)的部分成員變量還是會被逆向析構(gòu)的)
(3) 當(dāng)對象發(fā)生部分構(gòu)造時,已經(jīng)構(gòu)造完畢的子對象將會逆序地被析構(gòu);
?
網(wǎng)上的一個栗子:
一個實例對象的構(gòu)造:
第一步,分配足夠的內(nèi)存,如果失敗就是棧溢出或拋出std::bad_alloc的異常,所以在這步你不用擔(dān)心內(nèi)存泄露,而且這一步你是不能插手的,如果這步成功,就進(jìn)入第二步。
new運算符的實現(xiàn)保證了內(nèi)存泄漏不會發(fā)生。例如
T *p =?new?T;
將被編譯器轉(zhuǎn)換給類似下面的樣子:(其實和我們自己釋放已經(jīng)申請的資源的思想流程是一樣的)
// 第一步,分配原始內(nèi)存,若失敗則拋出bad_alloc異常 try {// 第二步,調(diào)用構(gòu)造函數(shù)構(gòu)造對象new (p)T; // placement new: 只調(diào)用T的構(gòu)造函數(shù) } catch(...) {delete []p; // 釋放第一步分配的內(nèi)存throw; // 重拋異常,通知應(yīng)用程序 } 第二步,調(diào)用構(gòu)造函數(shù),在通常情況下,如果構(gòu)造函數(shù)為空或沒有進(jìn)行動態(tài)內(nèi)存分配,你就不用關(guān)心內(nèi)存泄露了你需要關(guān)心的是構(gòu)造函數(shù)中有動態(tài)內(nèi)存分配
class A {char* str[10]; public:A(){for(int i=0;i<10;i++)str[i]=NULL; //對str[]初始化,這是必須的,不然再后面delete就會出現(xiàn)問題try{for(int i=0;i<10;i++)str[i]=new char[1024*1024*1024]; //要來就來狠的 }catch(bad_alloc){for(int i=0;i<10;i++)delete []str[i]; //放心,即使delete NULL是不會出問題的throw; //就拋出這個bad_alloc, 這才是構(gòu)造函數(shù)拋出去的異常,外層會撲捉到,并且析構(gòu)函數(shù)不會被調(diào)用 }}~A(){for(int i=0;i<10;i++)delete []str[i]; } }; int main() {A *pA=NULL;try{pA=new A;}catch(bad_alloc){cout<<"Out of memory"<<endl;}delete pA;return 0; } pA是用NULL初始化的,即使在給A分配內(nèi)存時(第一步)失敗,也不會導(dǎo)致后面的delete?pA出錯。
?
對于構(gòu)造函數(shù)可能失敗的做法一般有兩種
1. 在構(gòu)造函數(shù)中拋出異常,本對象構(gòu)造未完成,它的析構(gòu)函數(shù)不會被調(diào)用。當(dāng)然,我們有義務(wù)釋放已經(jīng)分配到的資源。簡單,最常見。
2. 把資源的初始化工作放在另一個單獨函數(shù)中,比如?bool?init(...),由對象創(chuàng)建者(比如工廠方法)先調(diào)用構(gòu)造函數(shù),再調(diào)用init方法。ATL中常見。
轉(zhuǎn)載于:https://www.cnblogs.com/Lunais/p/5674123.html
總結(jié)
以上是生活随笔為你收集整理的构造函数失败_抛出异常的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设计模式之笔记--简单工厂模式(Simp
- 下一篇: 18 Loader 总结