複製鏈接
請複製以下鏈接發送給好友

棧展開

鎖定
棧展開(stack unwinding)是指,如果在一個函數內部拋出異常,而此異常並未在該函數內部被捕捉,就將導致該函數的運行在拋出異常處結束,所有已經分配在棧上的局部變量都要被釋放。 [1] 
中文名
棧展開
外文名
stack unwinding
所屬學科
計算機
所屬領域
計算機編程

棧展開帶來的危害

在棧展開的過程中,如果被釋放的局部變量中有指針,而該指針在此前已經用new運算申請了空間,就有可能導致內存泄露。因為棧展開的時候並不會自動對指針變量執行delete(或delete)操作。 [1] 

棧展開內存泄露

因此,在有可能發生異常的函數中,在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] 
(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)。這樣可以保留使用指針的編程習慣,方便程序猿編寫和維護。
參考資料
  • 1.    陳剛.C++高級進階教程:武漢大學出版社,2008:371-373