在C++的異常處理中,當異常被throw後,從進入try塊起,到異常被catch前,在這期間棧上構造的所有對象都會被自動析構,這一過程稱之爲棧自旋。
一、對於棧上的對象
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout<<"A()"<<endl;
}
~A()
{
cout<<"~A()"<<endl;
}
};
int InternalFunc(void)
{
A a;
throw(static_cast<int>(0));
cout<<"InternalFunc normal"<<endl;
}
int ExternalFunc(void)
{
A b;
InternalFunc();
cout<<"ExternalFunc normal"<<endl;
}
int main(void)
{
try {
ExternalFunc();
}catch(int x){
cout<<x<<endl;
}catch(...){
cout<<"exception error"<<endl;
}
return 0;
}
最後的輸出結果爲:
A()
A()
~A()
~A()
0
我們可以看到,在異常被throw後,程序一層一層地向上,像乘坐直通車一樣找到對應的catch,這之間棧上的對象會被自動地析構,於是發生了兩次構造兩次析構。
二、對於堆上的空間(特別注意)
如果我們在try塊中申請了堆上的空間,當異常被throw後,catch之前,程序並不會隱式地釋放堆上所申請的空間,這樣就會造成內存泄漏。
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout<<"A()"<<endl;
}
~A()
{
cout<<"~A()"<<endl;
}
};
int InternalFunc(void)
{
A *p = new A;
throw(static_cast<int>(0));
cout<<"InternalFunc normal"<<endl;
}
int ExternalFunc(void)
{
A *p = new A;
InternalFunc();
cout<<"ExternalFunc normal"<<endl;
}
int main(void)
{
try {
ExternalFunc();
}catch(int x){
cout<<x<<endl;
}catch(...){
cout<<"exception error"<<endl;
}
return 0;
}
最後輸出的結果是:
A()
A()
0
可以看到,只發生了兩次構造,並未析構。因爲棧自旋時將那兩個指針看作要銷燬的對象,自然只移動了棧頂指針,並未free掉所指向的堆內存,自然堆上的對象就不會被析構了。