標籤:智能指標 unique-ptr shared-ptr weak-ptr auto-ptr
1. 傳統指標存在的問題
傳統指標存在諸多的問題,比如指標所指向的對象的生命週期問題,掛起引用(dangling references),以及記憶體泄露(memory leaks).
如下是一個傳統指標的使用過程
void Foo() { int *iPtr = new int[5]; // manipulate the memory block // ... // ... // ... delete[] iPtr;}
以上代碼將正常運行且記憶體將被合理釋放,但是使用指標常會發生一些意想不到的事情,比如訪問一個非法的記憶體單元,除0操作,以及根據一些判斷條件處理的返回return 語句。
2. 什麼是智能指標(Smart Pointer)
智能指標是RAII(Resource Acquisition is initialization)用來動態分配記憶體。它提供了普通指標的所有介面外加少數異常處理。在構造階段,它將分配記憶體,而在非其範圍內將自動釋放所佔有的記憶體。
在C++98中,使用 auto_ptr來解決上述問題。
2.1 auto_ptr
#include <iostream>#include <memory>using namespace std;class Test {public: Test(int a = 0) : m_a(a) {} ~Test() { cout << "Calling destructor" << endl; }public: int m_a;};int main(){ auto_ptr<Test> p(new Test(5)); cout << p->m_a << endl; return 0;}
輸出結果:
上述代碼將智能的釋放相關的記憶體。
#include <iostream>#include <memory>using namespace std;class Test {public: Test(int a = 0) : m_a(a) {} ~Test() { cout << "Calling destructor" << endl; }public: int m_a;};void Fun(){ int a = 0, b = 5, c; if(a == 0) { throw "Invalid divisor"; } c = b / a; return;}int main(){ try { auto_ptr<Test> p(new Test(5)); Fun(); cout << p->m_a << endl; } catch(...) { cout << "Something has gone wrong" << endl; } return 0;}
在上述代碼中,即使異常拋出,指標照樣被正常釋放。這是因為當異常拋出時,棧鬆綁(stack unwinding)。 當所有屬於try block的本機物件被銷毀時,指標p不在範圍中而被釋放。
問題1.
至少從目前來說auto_ptr是智能的。但是它有一個非常本質的缺點:auto_ptr會傳遞它本身的ownership當其被賦值給另一個auto_ptr對象。正如下述程式所示,一個auto_ptr對象傳遞給函數Fun()中的auto_ptr對象時,其ownership,或者說是smartness將不再返回給原auto_ptr所指向的p。
#include <iostream>#include <memory>using namespace std;class Test {public: Test(int a = 0) : m_a(a) {} ~Test() { cout << "Calling destructor" << endl; }public: int m_a;};void Fun(auto_ptr<Test> p1){ cout << p1->m_a << endl; cout << "Fun() end" << endl;}int main(){ auto_ptr<Test> p(new Test(5)); Fun(p); cout << p->m_a << endl; return 0;}
運行結果:
以上程式將crash因為存在野指標auto_ptr。上述代碼奔潰的主要原因是,原先的p佔有對其自身分配記憶體的管理權。然而通過Fun()函數將其管理權轉給p1,此時因為p1的smartness,在其結束時將釋放其所指向的記憶體塊。而此時原先的p將再擁有任何記憶體,而導致在訪問時出現了null 指標,野指標的引用問題。
問題2.
auto_ptr不能使用於數組對象。 這裡的意思是不能使用於操作符new[]。
int main(){ auto_ptr<Test> p(new Test[5]); return 0;}
上述代碼將runtime error。因為對於auto_ptr而言,其調用的是delete而非delete []。
問題3.
auto_ptr不能使用於一些標準的容器庫。比如vector,list,map等等。
C++11提出了新型的智能指標,並且都賦予了其相應的意圖。
2.2 shared_ptr
未完待續…
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
【C++】智能指標(Smart Pointer)