现在的位置: 首页 > 综合 > 正文

《STL源码剖析》—_auto_ptr.h阅读笔记

2017年10月12日 ⁄ 综合 ⁄ 共 3998字 ⁄ 字号 评论关闭

auto_ptr是常用的智能指针,其实现很简单,源代码也很短,但是中间有个代理类auto_ptr_ref用的很巧妙,值得学习。

/*
 * Copyright (c) 1997-1999
 * Silicon Graphics Computer Systems, Inc.
 *
 * Copyright (c) 1999
 * Boris Fomitchev
 *
 * This material is provided "as is", with absolutely no warranty expressed
 * or implied. Any use is at your own risk.
 *
 * Permission to use or copy this software for any purpose is hereby granted
 * without fee, provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 *
 */

#ifndef _STLP_AUTO_PTR_H
#define _STLP_AUTO_PTR_H

_STLP_BEGIN_NAMESPACE
// implementation primitive
//auto_ptr基类,声明指针和指针初始化操作
class __ptr_base {
public:
  void* _M_p;
  void  __set(const volatile void* p) { _M_p = __CONST_CAST(void*,p); }
  void  __set(void* p) { _M_p = p; }
};
//使用auto_ptr_ref,在源代码后面举例说明
template <class _Tp>
class auto_ptr_ref {
public:
  __ptr_base& _M_r;
  _Tp* const _M_p;
   //_M_r是引用,_M_p是常量指针,在构造函数初始化列表初始化
  auto_ptr_ref(__ptr_base& __r, _Tp* __p) : _M_r(__r), _M_p(__p) {  }
   //释放,把基类_M_r指针设为空
  _Tp* release() const { _M_r.__set(__STATIC_CAST(void*, 0)); return _M_p; }

private:
  //explicitely defined as private to avoid warnings:
  //显示定义,避免警告。
  //重载“=”为私有函数,不允许调用
  typedef auto_ptr_ref<_Tp> _Self;
  _Self& operator = (_Self const&);
};

template<class _Tp>
class auto_ptr :  public __ptr_base {
public:
  typedef _Tp element_type;
  typedef auto_ptr<_Tp> _Self;

  _Tp* release() _STLP_NOTHROW {
    _Tp* __px = this->get();
    this->_M_p = 0;
    return __px;
  }

  void reset(_Tp* __px = 0) _STLP_NOTHROW {
    _Tp* __pt = this->get();
    if (__px != __pt)
      delete __pt;
    this->__set(__px);
  }

  _Tp* get() const _STLP_NOTHROW
#if !defined (__GNUC__) || (__GNUC__ > 2)
	//像C语言一样,用static_cast<>
  { return __STATIC_CAST(_Tp*, _M_p); }
#else
	//像C++一样用reinterpret
  { return __REINTERPRET_CAST(_Tp*, _M_p); }
#endif

#if !defined (_STLP_NO_ARROW_OPERATOR)
	//返回指针
  _Tp* operator->() const _STLP_NOTHROW {
  //断言,确保返回指针不是空指针
    _STLP_VERBOSE_ASSERT(get() != 0, _StlMsg_AUTO_PTR_NULL)
    return get();
  }
#endif
	//返回引用
  _Tp& operator*() const _STLP_NOTHROW {
  //断言,确保指针不是空指针,这样才可以解引用
    _STLP_VERBOSE_ASSERT(get() != 0, _StlMsg_AUTO_PTR_NULL)
    return *get();
  }
	//显示构造函数,不允许隐式调用
  explicit auto_ptr(_Tp* __px = 0) _STLP_NOTHROW { this->__set(__px); }

 /*
 复制构造函数,需要注意的是复制构造函数是auto_ptr传递的是指针的所有权。
 因为要修改传入参数的所有权,所以传入参数不是const(不同于其他复制构造函数)
 auto_ptr<int>p1(new int(10));
 auto_ptr<int>p2(p1);
 p2指向new int(10)后,p1就成了空指针,他们不能共享所有权,因此auto_ptr不能作为
 容器元素,因为容器元素要支持拷贝和复制
 */
#if defined (_STLP_MEMBER_TEMPLATES)
#  if !defined (_STLP_NO_TEMPLATE_CONVERSIONS)
  template<class _Tp1> auto_ptr(auto_ptr<_Tp1>& __r) _STLP_NOTHROW {
    _Tp* __conversionCheck = __r.release();
    this->__set(__conversionCheck);
  }
#  endif
  template<class _Tp1> auto_ptr<_Tp>& operator=(auto_ptr<_Tp1>& __r) _STLP_NOTHROW {
    _Tp* __conversionCheck = __r.release();
    reset(__conversionCheck);
    return *this;
  }
#endif

	//同类型auto_ptr作为复制构造函数参数,不用模板
  auto_ptr(_Self& __r) _STLP_NOTHROW { this->__set(__r.release()); }
	//赋值操作符和复制构造函数类型,传递的是所有权,不是值传递
  _Self& operator=(_Self& __r) _STLP_NOTHROW {
    reset(__r.release());
    return *this;
  }
	//析构函数很简单,只是调用指针指向对象的析构函数,释放指针指向的空间
	//delete而不是delete[],所以auto_ptr不能指向数组
  ~auto_ptr() _STLP_NOTHROW { /* boris : reset(0) might be better */ delete this->get(); }

  
  //使用auto_ptr_ref,在源代码后面举例说明
  auto_ptr(auto_ptr_ref<_Tp> __r) _STLP_NOTHROW
  { this->__set(__r.release()); }

  _Self& operator=(auto_ptr_ref<_Tp> __r) _STLP_NOTHROW {
    reset(__r.release());
    return *this;
  }

#if defined(_STLP_MEMBER_TEMPLATES) && !defined(_STLP_NO_TEMPLATE_CONVERSIONS)
  template<class _Tp1> operator auto_ptr_ref<_Tp1>() _STLP_NOTHROW
  { return auto_ptr_ref<_Tp1>(*this, this->get()); }
  template<class _Tp1> operator auto_ptr<_Tp1>() _STLP_NOTHROW
  { return auto_ptr<_Tp1>(release()); }
#else
  operator auto_ptr_ref<_Tp>() _STLP_NOTHROW
  { return auto_ptr_ref<_Tp>(*this, this->get()); }
#endif
};
_STLP_END_NAMESPACE

#endif /* _STLP_AUTO_PTR_H */

// Local Variables:
// mode:C++
// End:

auto_ptr是智能指针。在赋值(复制构造函数或赋值操作符)的时候是传递指针所用权,而不是传递值。所以在复制构造函数或复制操作符函数要取消原来指针的所有权,因此就不能把传入的参数声明为const类型。但是有些情况下,必须要声明为const类型,例如

auto_ptr<int> p(auto_ptr<int>(new int(10));

使用临时对象时,必须用const修饰

auto_ptr(auto_prt<int> const&),而auto_ptr要修改原来指针的所有权,声明成了auto_ptr(auto_prt<int> &),上面代码不能通过编译。

再例如

auto_ptr<int> p1(NULL);

p1=(auto_ptr<int>(new int(10));

有和上面一样的问题,临时对象是右值,非const&不能指向右值。

这样情况下就引入了auto_ptr_ref,auto_ptr可以隐式转换为auto_ptr_ref,这样上面的程序就不会出错。


抱歉!评论已关闭.