C 智慧型指標之auto ptr

2021-06-26 11:08:21 字數 3798 閱讀 5026

c++中指標申請和釋放記憶體通常採用的方式是new和delete。然而標準c++中還有乙個強大的模版類就是auto_ptr,它可以在你不用的時候自動幫你釋放記憶體。下面簡單說一下用法。

[cpp]view plain

copy

用法一:  

std::auto_ptrm_example(new myclass());  

用法二:  

std::auto_ptrm_example;  

m_example.reset(new myclass());  

用法三(指標的賦值操作):  

std::auto_ptrm_example1(new myclass());  

std::auto_ptrm_example2(new myclass());  

m_example2=m_example1;  

則c++會把m_example所指向的記憶體**,使m_example1 的值為null,所以在c++中,應絕對避免把auto_ptr放到容器中。即應避免下列**:

vector>m_example;

當用演算法對容器操作的時候,你很難避免stl內部對容器中的元素實現賦值傳遞,這樣便會使容器中多個元素被置位null,而這不是我們想看到的。

雖然,標準auto_ptr智慧型指標機制很多人都知道,但很少使用它。這真是個遺憾,因為auto_ptr優雅地解決了c++設計和編碼中常見的問題,正確地使用它可以生成健壯的**。本文闡述了如何正確運用auto_ptr來讓你的**更加安全——以及如何避免對auto_ptr危險但常見的誤用,這些誤用會引發間斷性發作、難以診斷的bug。

為什麼稱它為「自動」指標?auto_ptr只是眾多可能的智慧型指標之一。許多商業庫提供了更複雜的智慧型指標,用途廣泛而令人驚異,從管理引用的數量到提供先進的**服務。可以把標準c++ auto_ptr看作智慧型指標的ford escort(elmar注:可能指福特的一種適合家居的車型):乙個簡易、通用的智慧型指標,它不包含所有的小技巧,不像專用的或高效能的智慧型指標那麼奢華,但是它可以很好的完成許多普遍的工作,它很適合日常性的使用。

auto_ptr所做的事情,就是動態分配物件以及當物件不再需要時自動執行清理。這裡是乙個簡單的**示例,沒有使用auto_ptr所以不安全:

[cpp]view plain

copy

// 示例1(a):原始**  

void f()    

我們大多數人每天寫類似的**。如果f()函式只有三行並且不會有任何意外,這麼做可能挺好的。但是如果f()從不執行delete語句,或者是由於過早的返回,或者是由於執行函式體時丟擲了異常,那麼這個被分配的物件就沒有被刪除,從而我們產生了乙個經典的記憶體洩漏。

能讓示例1(a)安全的簡單辦法是把指標封裝在乙個「智慧型的」類似於指標的物件裡,這個物件擁有這個指標並且能在析構時自動刪除這個指標所指的物件。因為這個智慧型指標可以簡單的當成乙個自動的物件(這就是說,它出了作用域時會自動毀滅),所以很自然的把它稱之為「智慧型」指標:

[cpp]view plain

copy

// 示例1(b):安全**,使用了auto_ptr

void f()  

// 酷:當pt出了作用域時析構函式被呼叫,從而物件被自動刪除

現在**不會洩漏t型別的物件,不管這個函式是正常退出還是丟擲了異常,因為pt的析構函式總是會在出棧時被呼叫,清理會自動進行。

最後,使用乙個auto_ptr就像使用乙個內建的指標一樣容易,而且如果想要「撤銷」資源,重新採用手動的所有權,我們只要呼叫release()。

[cpp]view plain

copy

// 示例2:使用乙個auto_ptr

void g()  

// pt2不再擁有任何指標,所以不要試圖刪除它...ok,不要重複刪除

最後,我們可以使用auto_ptr的reset()函式來重置auto_ptr使之擁有另乙個物件。如果這個auto_ptr已經擁有了乙個物件,那麼,它會先刪除已經擁有的物件,因此呼叫reset()就如同銷毀這個auto_ptr,然後新建乙個並擁有乙個新物件:

[cpp]view plain

copy

// 示例 3:使用reset()

void h()  

// 最後pt出了作用域,第二個t也被刪除了

auto_ptr用法:

1. 需要包含標頭檔案。

2. constructor:explicit auto_ptr(x* p = 0) throw(); 將指標p交給auto_ptr物件託管。

3. copy constructor:auto_ptr(const auto_ptr&) throw(); templateauto_ptr(const auto_ptr& a) throw(); 指標的託管權會發生轉移。

4. destructor: ~auto_ptr(); 釋放指標p指向的空間。

5. 提供了兩個成員函式 x* get() const throw();       //返回儲存的指標

6. 物件中仍保留指標 x* release() const throw();     //返回儲存的指標,物件中不保留指標

auto_ptr實現關鍵點:

1. 利用特點「棧上物件在離開作用範圍時會自動析構」。

2. 對於動態分配的記憶體,其作用範圍是程式設計師手動控制的,這給程式設計師帶來了方便但也不可避免疏忽造成的記憶體洩漏,畢竟只有編譯器是最可靠的。

3. auto_ptr通過在棧上構建乙個物件a,物件a中wrap了動態分配記憶體的指標p,所有對指標p的操作都轉為對物件a的操作。而在a的析構函式中會自動釋放p的空間,而該析構函式是編譯器自動呼叫的,無需程式設計師操心。

多說無益,看乙個最實用的例子:

[cpp]view plain

copy

#include 

#include 

using

namespace std;  

class tc  

;  void foo(

bool isthrow)  

catch(

const

char* e)  

//delete ptc;              // 方法1

}  int main()  

catch(...)  

system("pause");  

}  

1. 如果採用方案1,那麼必須考慮到函式在因throw異常的時候釋放所分配的記憶體,這樣造成的結果是在每個分支處都要很小心的手動 delete ptc;。

2. 如果採用方案2,那就無需操心何時釋放記憶體,不管foo()因何原因退出, 棧上物件ptc的析構函式都將呼叫,因此託管在之中的指標所指的記憶體必然安全釋放。

至此,智慧型指標的優點已經很明了了。

但是要注意使用中的乙個陷阱,那就是指標的託管權是會轉移的。 例如在上例中,如果 auto_ptrptc(new tc);   auto_ptrptc1=ptc; 那麼,ptc1將擁有該指標,而ptc沒有了,如果再用ptc去引用,必然導致記憶體錯誤。

要避免這個問題,可以考慮使用採用了引用計數的智慧型指標,例如boost::shared_ptr等。auto_ptr不會降低程式的效率,但auto_ptr不適用於陣列,auto_ptr根本不可以大規模使用。 shared_ptr也要配合weaked_ptr,否則會很容易觸發迴圈引用而永遠無法**記憶體。 理論上,合理使用容器加智慧型指標,c++可以完全避免記憶體洩露,效率只有微不足道的下降(中型以上程式最多百分之一)。

C 智慧型指標 auto ptr

智慧型指標 auto ptr vc版本 擁有權管理和轉移 當乙個智慧型指標給另乙個智慧型指標初始化的時候,兩個智慧型指標將會同時指向乙個空間,這樣在物件析構的時候,會導致一塊空間釋放多次的問題,所以乙個物件從始至終只能擁有乙個智慧型指標,這樣就保證不會乙個物件多次釋放的問題.我們讓指標給指標初始化的...

C 智慧型指標(auto ptr)

智慧型指標 在c 中使用堆記憶體是非常頻繁的操作,堆記憶體的申請和釋放都由程式設計師自己管理。使用普通指標,容易造成堆記憶體洩露,二次釋放等問題,使用智慧型指標能更好的管理堆記憶體。c 11中引入了智慧型指標的概念,方便管理堆記憶體。棧 堆區別 棧 系統開闢 系統釋放 堆 手動開闢 手動釋放 設計 ...

C 智慧型指標auto ptr

template class auto ptr 建構函式 templateinline auto ptr auto ptr t p pointee p 拷貝建構函式 templateinline auto ptr auto ptr auto ptr rhs pointee rhs.release t...