STL源代码剖析-07 memory 智能指针auto_ptr

3109阅读 0评论2012-04-13 _Rayx
分类:C/C++

auto_ptr是众多智能指针中的一个,虽然它功能没有那些专用的智能指针强大和复杂,不过在大部分时候还是能够应付我们的工作。先看看代码最前面的:
  1. template<class _Tp1> struct auto_ptr_ref {
  2.   _Tp1* _M_ptr;
  3.   auto_ptr_ref(_Tp1* __p) : _M_ptr(__p) {}
  4. };
只有一个指针,并且传递给他的也是一个_Tp1类型的指针,然后用_M_ptr指向它!
再看它的构造函数:

  1. explicit auto_ptr(_Tp* __p = 0) __STL_NOTHROW : _M_ptr(__p) {}
  2.   auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {}

  3. #ifdef __STL_MEMBER_TEMPLATES
  4.   template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW
  5.     : _M_ptr(__a.release()) {}
  6. #endif /* __STL_MEMBER_TEMPLATES */
第一个构造函数用explicit,表示只能显式构造!由于后两个都用了release()方法,我们销后再讨论。
析构函数:

  1. ~auto_ptr() { delete _M_ptr; }
可以看到它删除了_M_ptr指向的内存,就是这样,在构造函数中申请内存,在析构函数中删除!这样就不用我们自己管理了,防止因为忘记delete而造成内存泄露。

  1. _Tp& operator*() const __STL_NOTHROW {
  2.     return *_M_ptr;
  3.   }
  4.   _Tp* operator->() const __STL_NOTHROW {
  5.     return _M_ptr;
  6.   }
重载了*和->,使它们可以看起来像原来的指针一样使用。

  1. _Tp* get() const __STL_NOTHROW {
  2.     return _M_ptr;
  3.   }
  4.   _Tp* release() __STL_NOTHROW {
  5.     _Tp* __tmp = _M_ptr;
  6.     _M_ptr = 0;
  7.     return __tmp;
  8.   }
  9.   void reset(_Tp* __p = 0) __STL_NOTHROW {
  10.     if (__p != _M_ptr) {
  11.       delete _M_ptr;
  12.       _M_ptr = __p;
  13.     }
  14.   }
get()返回原始指针,这样就能在需要使用原始类型的时候大显身手了。
release()释放指针,注意,它并没有释放内存。
reset()重置指针,释放内存并将它指向一个新的对象。它先判断是不是reset到同一对象,否则delete后就会出问题了!

重载的赋值运算符:


  1. auto_ptr& operator=(auto_ptr& __a) __STL_NOTHROW {
  2.     if (&__a != this) {
  3.       delete _M_ptr;
  4.       _M_ptr = __a.release();
  5.     }
  6.     return *this;
  7.   }

  8. #ifdef __STL_MEMBER_TEMPLATES
  9.   template <class _Tp1>
  10.   auto_ptr& operator=(auto_ptr<_Tp1>& __a) __STL_NOTHROW {
  11.     if (__a.get() != this->get()) {
  12.       delete _M_ptr;
  13.       _M_ptr = __a.release();
  14.     }
  15.     return *this;
  16.   }
  17. #endif /* __STL_MEMBER_TEMPLATES */
=运算符如果不是操作同一个对象的时候会先删除左操作数指向的对象,后面指向右操作数指向的对象,再release()右操作数,从前面可以看到release() 只是将指针置空,并没有释放内存。从这里可以看到永远只有一个auto_ptr对象指向它。呃当然,通过精心构造,还是可以有多个auto_ptr指向同一个对象的,但是通过=却可以防止多个auto_ptr指向同一个。

再回头看看它的拷贝构造函数,是的,也防止了多个auto_ptr指向同一个对象,这其实是为了防止在析构的时候多次delete掉同一块内存。因为多次delete掉一个对象在C++是未定义的。
再看看析构函数:它只是delete,并没有将指针置为NULL! 呃,delete NULL好像可以多次,因为C++中定义了它什么都不做。

所以使用auto_ptr一个正确的做法就是这样:auto_ptr my_ptr(new MyClass());而不是传一个MyClass*进来!

release()中是将指针置为NULL了就是为了防止析构时将对象删掉!
不知道出于什么考虑在析构函数中delete后没有将指针置为NULL?








上一篇:STL源代码剖析-06 stl_uninitialized.h
下一篇:STL源代码剖析-08 迭代器,type-traits (1)