3 智慧型指標std auto ptr

2021-09-06 11:50:32 字數 3191 閱讀 7335

std::auto_ptr

對於編譯器來說,智慧型指標實質是乙個棧物件,而並非指標型別。

智慧型指標通過建構函式獲取堆記憶體的管理所有權,而在其生命期結束時,再通過析構函式釋放由它所管理的堆記憶體。

所有智慧型指標都過載了「operator->」操作符,直接返回物件的引用,用以操作物件。訪問智慧型指標原來的方法則使用「.」操作符。

訪問智慧型指標包含的裸指標則可以用get()函式。

由於智慧型指標是乙個物件,所以if(spobject)永遠為真。要判斷智慧型指標的裸指標是否為空,需要這樣判斷:if(spobject.get())。

智慧型指標包含了reset()方法,如果不傳遞引數(或傳遞null),則智慧型指標會釋放當前管理的記憶體。如果傳遞乙個物件,則智慧型指標會釋放當前物件,來管理新傳入的物件。

std::auto_ptr 示例及分析

<1>**如下:

1 #include2 #include3

using

namespace

std;45

class

int6

13 ~int()

1417

void

printvalue()

1821

void setvalue(int

nsetvalue)

2225

26private:27

intm_nvalue;

28};

2930

void

testauto_ptr1()

3141

//spint棧物件結束生命期,隨之析構堆物件int(10),同時釋放記憶體資源42}

4344

void

main()

4548

49//

執行結果如下:

50/*

51constructor: 10

52printvalue: 10

53printvalue: 20

54printvalue: 30

55destructor: 30

56*/

上面為一般情況下使用std::auto_ptr的**示例,一切看似都蠻不錯哈,說一千道一萬,無論如何不用咱們再顯式使用那該死的delete了。

但是,實際的使用中的情況要比這個複雜得多,也不選多麼複雜的!眼下咱比如:智慧型指標的拷貝構造以及賦值構造等。請看以下分析。

<2> 新增測試函式2

**以及注釋如下:

1

void

testauto_ptr2()

211 }

最終可以看到如上**導致崩潰!居然崩潰了?什麼原因導致崩潰呢?

在網上看到各種版本的解釋。趙本山大叔有一句話:「你刨得不深,我要往祖墳上刨!」

跟進std::auto_ptr的原始碼,其賦值建構函式**如下:

1

//std::auto_ptr賦值建構函式

23 _myt& operator=(_myt&_right) _throw0()4 8

9 _ty *release() _throw0()

10 15

16void reset(_ty *_ptr = 0

)17

三個函式,呼叫關係一目了然,執行結果很清晰:目標物件獲取源物件所管理的記憶體所有權,同時把源物件置空。

通過上面的原始碼分析,我們可以看到: 崩潰的罪魁禍首是 spint2 = spint; 就這行**,發生兩個重要過程:

1> spint2完全奪取了spint的記憶體管理所有權;

2> 置spint為空。

由於spint已置為空,最後再使用必然導致崩潰。

細心的人估計看到了原始碼函式後面的那個關鍵字throw,關於這個關鍵字請參見隨筆《函式後面加throw關鍵字》

所以,使用std::auto_ptr時,絕對不能使用「operator=」操作符。

這也正所謂std::auto_ptr是支援毀壞式複製語義及raii的智慧型指標的全部體現。

關於raii慣用法,請參見隨筆《raii慣用法詳解》。

好吧!再看一種實際使用的例子,**如下:

1

void

testauto_ptr3()

29 }

執行結果為:constructor: 100

看到有什麼異常了嗎?沒有輸出「destructor: 100」,那也就意味著我們建立出來的物件竟然沒有被析構,這個可不科學!

上面我們才強調了std::auto_ptr是raii的智慧型指標,這裡沒有析構物件是否導致記憶體洩漏呢?

當我們不想讓spint3繼續生存下去時,第一反應應該是呼叫release()函式釋放記憶體,結果卻導致記憶體洩漏。

在記憶體受限系統中,假如spint3占用太多記憶體,我們會考慮一旦使用完成後,立刻歸還,而不是等到spint3結束生命期後才歸還。

由於上面已經有release()函式的實現原始碼,所以,這裡的記憶體洩漏原因其實很明白,不再贅述。

那麼正確的**應該是怎樣呢?根據上面的實際需求再不導致記憶體洩漏情況下,如下實現:

1

void

testauto_ptr3() 29

}10//或

11void

testauto_ptr3()

1218 }

<3> 總結:關於std::auto_ptr的使用,請注意以下幾點:

(1)盡量不要使用「operator=」(如果使用了,請不要再使用先前物件)。

(2)記住release()函式不會釋放物件,僅僅歸還所有權。

(3)std::auto_ptr最好不要當成引數傳遞(讀者可以自行寫**確定為什麼不能)。

(4)由於std::auto_ptr的「operator=」問題,由其管理的物件不能放入std::vector等容器中。

(5)auto_ptr儲存的指標應該為null或者指向動態分配的記憶體塊。

(6)auto_ptr儲存的指標應該指向單一物件(是new出來的,而不是new出來的)。

(7)兩個auto_ptr物件不會同時指向同一塊記憶體塊(要明白兩個auto_ptr物件賦值會發生什麼)。

使用std::auto_ptr的侷限性很大,可謂防不勝防。

good good study, day day up.

順序   選擇  迴圈  總結

智慧型指標std auto ptr

std auto ptr 對於編譯器來說,智慧型指標實質是乙個棧物件,而並非指標型別。智慧型指標通過建構函式獲取堆記憶體的管理所有權,而在其生命期結束時,再通過析構函式釋放由它所管理的堆記憶體。所有智慧型指標都過載了 operator 操作符,直接返回物件的引用,用以操作物件。訪問智慧型指標原來的方...

std auto ptr智慧型指標使用

此篇博文記錄編碼過程中遇到的有關智慧型指標std auto ptr的使用方法,由於是記錄使用過程中遇到的方法所以不會將該智慧型指標的全部方法簡紹清楚,有關std auto ptr的詳細教程請參考相應的教程。1 reset pam 方法 使用pam重置智慧型指標,如 std auto ptrmessa...

智慧型指標3

include include using namespace std define test smartptr class stub class sentry sentry private int lock template class refcountingtraits void unrefer...