您的位置:首页 > 编程语言 > C语言/C++

C++ Standard Stl -- SGI STL源码学习笔记(01) auto_ptr

2012-07-25 07:03 706 查看
写在前面:

    学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是通过两部分实现的. 曲线实现的方法确实是很精巧的~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: