天天看點

C++智能指針auto_ptr詳解 auto_ptr 特性與使用技巧 auto_pstr的實作

auto_ptr是c++标準庫中()為了解決資源洩漏的問題提供的一個智能指針類模闆(注意:這隻是一種簡單的智能指針)

auto_ptr的實作原理其實就是raii,在構造的時候擷取資源,在析構的時候釋放資源,并進行相關指針操作的重載,使用起來就像普通的指針。

1

但是由于其構造函數聲明為explicit的,是以不能通過飲食轉換來構造,隻能顯示調用構造函數

例如

2

下面主要分析一下auto_ptr的幾個要注意的地方:

auto_ptr與boost庫中的share_ptr不同的,auto_ptr沒有考慮引用計數,是以一個對象隻能由一個auto_ptr所擁有,在給其他auto_ptr指派的時候,會轉移這種擁有關系。

從上可知由于在指派,參數傳遞的時候會轉移所有權,是以不要輕易進行此類操作。

比如:

“`

std::auto_ptr pa(new classa());

bad_print(pa); //丢失了所有權

pa->…; //error

為了防止資源洩漏,我們通常在構造函數中申請,析構函數中釋放,但是隻有構造函數調用成功,析構函數才會被調用,換句話說,如果在構造函數中産生了異常,那麼析構函數将不會調用,這樣就會造成資源洩漏的隐患。

比如,如果該類有2個成員變量,指向兩個資源,在構造函數中申請資源a成功,但申請資源b失敗,則構造函數失敗,那麼析構函數不會被調用,那麼資源a則洩漏。

為了解決這個問題,我們可以利用auto_ptr取代普通指針作為成員變量,這樣首先調用成功的成員變量的構造函數肯定會調用其析構函數,那麼就可以避免資源洩漏問題。

auto_ptr不能共享所有權,即不要讓兩個auto_ptr指向同一個對象。

auto_ptr不能指向數組,因為auto_ptr在析構的時候隻是調用delete,而數組應該要調用delete[]。

auto_ptr隻是一種簡單的智能指針,如有特殊需求,需要使用其他智能指針,比如share_ptr。

auto_ptr不能作為容器對象,stl容器中的元素經常要支援拷貝,指派等操作,在這過程中auto_ptr會傳遞所有權,那麼source與sink元素之間就不等價了。

參照stl-3.3源碼memeory檔案

auto_ptr隻有一個私有成員變量_m_ptr:

3

其中 __stl_nothrow宏在stl_config.h檔案中定義:

異常說明throw()在成員函數後面,這些成員函數将不抛出異常.

構造函數預設參數為null,在使用的時候可以不傳參數.

使用explicit,禁止參數的自動類型轉換.

這裡發現沒有使用const 限制參數

這個auto_ptr的功能有關,在使用複制構造函數的時候,不僅複制出一個和原對象一樣的對象,同時需要取消其控制權.

4

5

realease實作的功能就是将原智能指針的控制權取消.

傳回智能指針指向對象的指針.

6

reset函數提供了預設參數,功能是取消auto_ptr對原對象的控制權,并選擇性提供一個新的對象控制權.

其中=運算符,很關鍵,因為這個函數實作了智能指針的獨占性

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

auto_ptr_ref的實作很簡單,與auto_ptr中的幾個成員函數相關,完成輔助功能.為什麼需要提供auto_ptr_ref這樣一個輔助結構呢?

前面說過auto_ptr功能主要是實作對對象控制權的安全控制,所在它的複制構造函數沒有對參數進行const限制,因為需要修改.而這還涉及到标準c++左值右值的概念.

好吧,我們隻讨論标準c++,後面會說明為什麼這種實作的方式是為了标準c++考慮的.

lvalue && rvalue 關于左值 右值的具體分析與區分,網上有很多部落格和文章中都有說過.來看看比較權威的說明: the names rvalue and lvalue come originally from the assignment expression expr1 = expr2, in which the left operand expr1 must be a (modifiable) lvalue (“left value”). however, an lvalue is perhaps better considered as representing an object locator value. thus, it is an expression that designates an object by name or address(pointer or reference). lvalues need not be modifiable. for example, the name of a constant object is a nonmodifiable lvalue. all expressions that are not lvalues are rvalues. in particular, temporary objects created explicitly (t()) or as the result of a function call are rvalues.      the c++ standard library by nicolai m. josuttis an ordinary copy constructor can copy an rvalue, but to do so it must declare its parameter as a reference to a const object.

也就是說當給一個複制構造函數傳遞參數的時候,如果是右值,則構造函數參數必須是const reference.

而前面auto_ptr的複制構造函數卻不是這樣子的. 是以在實作的時候添加了auto_ptr_ref輔助來實作.實作的機制是通過auto_ptr_ref實作一個右值到中間左值的轉化過程.

引用對象的定義如下

是以auto_ptr需要提供類類型轉換,然後還需要提供重載的複制構造函數.下面就是這兩個函數:

同樣引入新增了=運算符重載和指派構造函數

這也是為什麼當看到源碼的時候發現auto_ptr是通過兩部分實作的.

曲線實作的方法确實是很精巧的

下面是我自己實作的源碼

轉載:http://blog.csdn.net/gatieme/article/details/50939155

繼續閱讀