棧展開(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=1there is no destructor invoked this is A's constructor, num=22this is A's destructor, num=2A'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()。這樣可以保留使用指針的編程習慣,方便程式猿編寫和維護。