棧展開(stack unwinding)是指,如果在一個函式內部拋出異常,而此異常並未在該函式內部被捕捉,就將導致該函式的運行在拋出異常處結束,所有已經分配在棧上的局部變數都要被釋放。
基本介紹
- 中文名:棧展開
- 外文名:stack unwinding
- 所屬學科:計算機
- 所屬領域:計算機編程
帶來的危害,記憶體泄露,
帶來的危害
在棧展開的過程中,如果被釋放的局部變數中有指針,而該指針在此前已經用new運算申請了空間,就有可能導致記憶體泄露。因為棧展開的時候並不會自動對指針變數執行delete(或delete)操作。
記憶體泄露
因此,在有可能發生異常的函式中,在C++編程中,可以利用“智慧型指針”auto_ptr來防止記憶體泄露。參考如下程式。
#include <iostream>
#include <memory>
using namespace std;
class A{
int num;
public:
A(int i):num(i){
cout<<"this is A's constructor, num="<<num<<endl;
}
~A(){
cout<<"this is A's destructor, num="<<num<<endl;
}
void show(){
cout<<num<<endl;
}
};
void autoptrtest1(){
A* pa=new A(1);
throw 1;
delete pa;
}
void autoptrtest2(){
auto_ptr<A> pa(new A(2));
pa->show();
throw 2;
}
int main(){
try{
autoptrtest1();
}
catch(int){
cout<<"there is no destructor invoked"<<endl;
}
cout<<endl;
try{
autoptrtest2();
}
catch(int){
cout<<"A's destructor does be invoked"<<endl;
}
}
程式的輸出結果:
this is A's constructor, num=1
there is no destructor invoked
this is A's constructor, num=2
2
this is A's destructor, num=2
A's destructor does be invoked
在解讀上面的這段程式的時候,要注意以下幾點。
(1)在函式(autoptrtest1)中,由於異常的發生,導致delete pa;無法執行,從而導致記憶體泄露。
(2)auto_ptr實際上是一個類模板,在名稱空間std中定義。要使用該類模板,必須包含頭檔案memory。auto_ptr的構造函式可以接受任何類型的指針,實際上是利用指針類型將該類模板實例化,並將傳入的指針保存在auto_ptr<T>對象中。
(3)在棧展開的過程中,auto_ptr<T>對象會被釋放,從而導致auto_ptr<T>對象的析構函式被調用。在該析構函式中,將使用delete運算符將保存在該對象內的指針所指向的動態對象被銷毀。這樣,就不會發生記憶體泄露了。
(4)由於已經對*和->操作符進行了重載,所以可以像使用普通的指針變數那樣使用auto_ptr<T>對象,如上面程式中的pa->(show)。這樣可以保留使用指針的編程習慣,方便程式猿編寫和維護。