C++程式丟擲異常後執行順序
1 解構函式中是否可以丟擲異常
首先我們看一個常見的問題,解構函式中是否可以丟擲異常。答案是C++標準指明解構函式不能、也不應該丟擲異常!
C++異常處理模型是為C++語言量身設計的,更進一步的說,它實際上也是為C++語言中面向物件而服務的。C++異常處理模型最大的特點和優勢就是對C++中的面向物件提供了最強大的無縫支援。那麼如果物件在執行期間出現了異常,C++異常處理模型有責任清除那些由於出現異常所導致的已經失效了的物件(也即物件超出了它原來的作用域),並釋放物件原來所分配的資源, 這就是呼叫這些物件的解構函式來完成釋放資源的任務,所以從這個意義上說,解構函式已經變成了異常處理的一部分。
下面我們來看看解構函式中不能丟擲異常的兩個理由:
1)如果解構函式丟擲異常,則異常點之後的程式不會執行,如果解構函式在異常點之後執行了某些必要的動作比如釋放某些資源,則這些動作不會執行,會造成諸如資源洩漏的問題。
2)通常異常發生時,c++的機制會呼叫已經構造物件的解構函式來釋放資源,此時若解構函式本身也丟擲異常,則前一個異常尚未處理,又有新的異常,會造成程式崩潰的問題。
那麼當無法保證在解構函式中不發生異常時, 該怎麼辦?
其實還是有很好辦法來解決的。那就是把異常完全封裝在解構函式內部,決不讓異常丟擲函式之外。這是一種非常簡單,也非常有效的方法。
//解構函式
~Class()
{
try{
}
catch(){ //這裡可以什麼都不做,只是保證catch塊的程式丟擲的異常不會被扔出解構函式之外。
}
}
2 程式丟擲異常後會怎樣
下面我們通過一個程式來觀察當程式中丟擲異常了是否會呼叫解構函式,異常丟擲中throw()後面的語句是否還會執行。程式如下,我們建立一個類,然後構造一個類物件,當丟擲異常我們看程式是否會進入解構函式以及throw()丟擲異常後面的程式:
#include<iostream>
using namespace std;
class setTry{
public:
setTry(){ //建構函式
cout << "start!" << endl; // 1
}
~setTry(){ //解構函式
cout << "end!" << endl; // 4
}
void dosomething(){
cout << "do something!" << endl; //類方法
}
};
int main(void)
{
setTry newOne;
try{
throw("error!"); //直接丟擲異常
newOne.dosomething();
}
catch (char* one){ //接收char*類異常
cout << one << endl; // 2
}
catch (...){ //接收其他型別異常
cout << "..." << endl;
}
cout << "return 0!"<<endl; // 3
return 0;
}
上面程式執行結就是按標註的1、2、3、4步驟輸出的,結果如下圖所示:
從執行結果就可以看出,丟擲異常try內部的throw()後面程式不會再執行,而try外部後面的程式會繼續執行。另外,解構函式在生存期結束也會被呼叫。