寫在前面:
學C++,到現在是第九天了,所以我只是在理論上對C++有淺顯的認知.對於實際應用,我還沒有實際的經驗.所以接下來對於SGI STL源碼分析的相關文章,更多的
就只是針對源碼的直接分析,是沒有關於實際應用場景經驗之談的.所以我們只談源碼,其他不談.
對於侯捷的那么本<<STL源碼剖析>>,我下載了PDF,只是粗略的瀏覽了一下目錄而已.想要說明的問題就是我沒有參考別人現成分析的書籍,可能在分析的過程中
有參考過一些博客中不錯的關於一些源碼閱讀過程中細節問題的解釋.如果分析的有誤,也是我自己分析的過錯,絕對不是參考XX人錯誤的分析資料,與他人無關.
auto_ptr的實現在memory文件中,包括所有的注釋也就只有134行代碼,所以是很少的.
1.__STL_BEGIN_NAMESPACE宏:
在代碼的開始就可以看到__STL_BEGIN_NAMESPACE宏,也很容易找到這個宏的定義:
宏定義在stl_config.h文件中.
# define __STL_BEGIN_NAMESPACE namespace std { # define __STL_END_NAMESPACE }
忽略掉在定義改宏的時候使用的其他宏,看到的宏定義就是上面所示. 就是定義命名空間std,這個很簡單.但是這里有另外一個問題,出去auto_ptr,在閱讀其他源碼的時
候,都會出現該宏,但是在源碼中存在着一個問題:在使用__STL_BEGIN_NAMESPACE宏的時候,有些源文件並沒有include "stl_config.h",(注意:不是<stl_config>).
這是個很奇怪的問題,我嘗試在很多的源文件中去尋找,但是都沒有找到.無從解釋~
2. __STL_NOTHROW宏:
同樣和上面宏一樣,__STL_NOTHROW宏在stl_config.h文件中定義:
# define __STL_NOTHROW throw()
這是異常說明,異常說明在成員函數后面,這些成員函數不拋出異常.
3. auto_ptr成員變量_M_ptr:
auto_ptr只有一個私有成員變量_M_ptr:
template <class _Tp> class auto_ptr { private: _Tp* _M_ptr;
4. 構造函數:
explicit auto_ptr(_Tp* __p = 0) __STL_NOTHROW : _M_ptr(__p) {}
a.構造函數默認參數為NULL,在使用的時候可以不傳參數.
b.使用explicit,禁止參數的自動類型轉換.
5. 復制構造函數:
auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {}
這里發現沒有使用const 限制參數. 這個auto_ptr的功能有關,在使用復制構造函數的時候,不僅復制出一個和原對象一樣的對象,同時需要取消其控制權.
realease函數:
_Tp* release() __STL_NOTHROW { _Tp* __tmp = _M_ptr; _M_ptr = 0; return __tmp; }
realease實現的功能就是將原智能指針的控制權取消.
6. get和reset函數:
a.get函數:
_Tp* get() const __STL_NOTHROW { return _M_ptr; }
返回智能指針指向對象的指針.
b.reset函數:
void reset(_Tp* __p = 0) __STL_NOTHROW { if (__p != _M_ptr) { delete _M_ptr; _M_ptr = __p; } }
reset函數提供了默認參數,功能是取消auto_ptr對原對象的控制權,並選擇性提供一個新的對象控制權.
7. auto_ptr_ref:
auto_ptr_ref的實現很簡單,與auto_ptr中的幾個成員函數相關,完成輔助功能.為什么需要提供auto_ptr_ref這樣一個輔助結構呢?
前面說過auto_ptr功能主要是實現對對象控制權的安全控制,所在它的復制構造函數沒有對參數進行const限制,因為需要修改.而這還涉及到標准C++左值右值的概念.
好吧,我們只討論標准C++,后面會說明為什么這種實現的方式是為了標准C++考慮的.
8. 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(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW : _M_ptr(__ref._M_ptr) {}
template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW { return auto_ptr_ref<_Tp1>(this->release()); }
這也是為什么當看到源碼的時候發現auto_ptr是通過兩部分實現的. 曲線實現的方法確實是很精巧的~