[c/c++]建構函式、解構函式中可不可以丟擲異常
阿新 • • 發佈:2019-01-05
usingnamespace std;
class A
{
public:
A()
{
cout <<"construction fun"<< endl;
throw1;
}
~A()
{
cout <<"destruction fun "<< endl;
throw2;
}
};
int main()
{
try
{
A a;
}
catch(...)//catch all
{
cout <<"caught!"<< endl;
}
system("pause");
return(0);
}
//輸出
//construction fun
//caught!
//註釋掉"throw 1",輸出
//construction fun
//destruction fun
//caught! #include <iostream>
“建構函式中如果丟擲異常,可見解構函式並沒有被呼叫,這樣子的話就產生了記憶體洩漏,所以如果要在建構函式丟擲異常之前,應該先把已經成功分配的資源釋放掉.
在C++中,經典的解決方案是使用STL的標準類auto_ptr,並且不要做過多的事情,只是能對成員變數的做初始化工作就好了。真的需要做其他複雜的初始化操作,完全可以提供一個Init或Start函式.
解構函式:
C++ 並 沒有禁止解構函式引發異常,但 是 C++ 十分不推薦這一做法。”
=================================================================================
=================================================================================
對於出錯處理,在C語言時代,使用的方法就是返回一個錯誤程式碼。預定義一系列的程式碼標識,當發生指定的錯誤時候,呼叫過程返回對應該型別錯誤的程式碼。
這種方法簡單,但是不適合複雜的應用。它會導致若干的問題,比如:
1.質量下降。使用錯誤程式碼,那麼必然需要在處理中對不同的程式碼進行分支處理。而分支過程包含錯誤可能性是其他方式的10倍。消除分支,程式碼將更加健壯。
2.增加成本。一方面,由於分支,那麼白盒法測試時的測試條件個數增多,延長測試過程;另一方面,控制流程的複雜性導致維護成本上升。
3. ....
class A
{
public:
A()
{
cout <<"construction fun"<< endl;
throw1;
}
~A()
{
cout <<"destruction fun "<< endl;
throw2;
}
};
int main()
{
try
{
A a;
}
catch(...)//catch all
{
cout
}
system("pause");
return(0);
}
//輸出
//construction fun
//caught!
//註釋掉"throw 1",輸出
//construction fun
//destruction fun
//caught! #include <iostream>
“建構函式中如果丟擲異常,可見解構函式並沒有被呼叫,這樣子的話就產生了記憶體洩漏,所以如果要在建構函式丟擲異常之前,應該先把已經成功分配的資源釋放掉.
在C++中,經典的解決方案是使用STL的標準類auto_ptr,並且不要做過多的事情,只是能對成員變數的做初始化工作就好了。真的需要做其他複雜的初始化操作,完全可以提供一個Init或Start函式.
解構函式:
C++ 並 沒有禁止解構函式引發異常,但 是 C++ 十分不推薦這一做法。”
=================================================================================
=================================================================================
對於出錯處理,在C語言時代,使用的方法就是返回一個錯誤程式碼。預定義一系列的程式碼標識,當發生指定的錯誤時候,呼叫過程返回對應該型別錯誤的程式碼。
這種方法簡單,但是不適合複雜的應用。它會導致若干的問題,比如:
1.質量下降。使用錯誤程式碼,那麼必然需要在處理中對不同的程式碼進行分支處理。而分支過程包含錯誤可能性是其他方式的10倍。消除分支,程式碼將更加健壯。
2.增加成本。一方面,由於分支,那麼白盒法測試時的測試條件個數增多,延長測試過程;另一方面,控制流程的複雜性導致維護成本上升。
3. ....
然而更糟糕的是,C++的構造/解構函式不允許有返回值,沒有返回型別,所以使用錯誤程式碼的方法被一錘打死了。也許有人會想到使用出參的方式返回錯誤代 碼,但是這個方法對於OO特性是存在衝突的,其詳細分析可參見參考資料2。因此,通知物件的構造失敗的唯一方法那就是在建構函式中丟擲異常。
建構函式異常,可以總結如下:
1.C++中通知物件構造失敗的唯一方法那就是在建構函式中丟擲異常;
2.建構函式丟擲異常時,解構函式將不會被執行;
3.丟擲異常時,其子物件將被逆序析構。(參考析構過程)
解構函式異常相對要複雜一些,存在一種衝突狀態,程式將直接崩潰:異常的被稱為“棧展開(stack unwinding)”【備註】的過程中時,從解構函式丟擲異常,C++執行時系統會處於無法決斷的境遇,因此C++語言擔保,當處於這一點時,會呼叫 terminate()來殺死程序。因此,當處理另一個異常的過程中時,不要從解構函式丟擲異常。概括總結如下:
1.C++中解構函式的執行不應該丟擲異常;
2.當在某一個解構函式中會有一些可能(哪怕是一點點可能)發生異常時,那麼就必須要把這種可能發生的異常完全封裝在解構函式內部,決不能讓它丟擲函式之外(這招簡直是絕殺!呵呵!);
3.丟擲異常時,其子物件將被逆序析構。(參考析構過程)
備註:
棧展開(stack unwinding):舉例來說,如果某人寫了throw Foo(),棧會被展開,以至throw Foo()和 } catch (Foo e) { 之間的所有的棧頁面被彈出。這被稱為棧展開(statck unwinding)