Friday, October 28, 2011

auto_ptr 和 shared_ptr

偶然的机会看到boost里还有一个shared_ptr型智能指针,费解,C++标准库里不是有auto_ptr了已经?我们先翻出源代码来看看。
先看auto_ptr,因为它比较简单。既然它在标准库里,那么我们就在gcc的代码中找,恩,最后确定在libstdc++-v3/include/backward/auto_ptr.h里面。说实话,auto_ptr真是太简单了,里面的私有变量就一个:
private:
_Tp* _M_ptr;
其它操作皆是围绕这个进行的,你自己猜都能猜到,看看吧,构造函数中的一个:
C++:
  1. explicit
  2. auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }
析构函数:
C++:
  1. ~auto_ptr() { delete _M_ptr; }
重载的赋值运算符:
C++:
  1. template<typename _Tp1>
  2. auto_ptr&
  3. operator=(auto_ptr<_Tp1>& __a) throw()
  4. {
  5. reset(__a.release());
  6. return *this;
  7. }
调用了自己的reset和release方法,按住不表,下面会介绍。重载的提领运算符:
C++:
  1. element_type&
  2. operator*() const throw()
  3. {
  4. _GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
  5. return *_M_ptr;
  6. }

成员运算符:
C++:
  1. element_type*
  2. operator->() const throw()
  3. {
  4. _GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
  5. return _M_ptr;
  6. }

get()方法:
C++:
  1. element_type*
  2. get() const throw() { return _M_ptr; }

release()方法:
C++:
  1. element_type*
  2. release() throw()
  3. {
  4. element_type* __tmp = _M_ptr;
  5. _M_ptr = 0;
  6. return __tmp;
  7. }

reset()方法:
C++:
  1. void
  2. reset(element_type* __p = 0) throw()
  3. {
  4. if (__p != _M_ptr)
  5. {
  6. delete _M_ptr;
  7. _M_ptr = __p;
  8. }
  9. }

这些应该没什么难理解的,可能除了那个成员运算符,只说一句:C++会把foo->bar()翻译成:(foo.operator->())->bar()。
从上面我们可以看出,auto_ptr明显没有计数引用,而shared_ptr和它的最大区别就是它有计数。shared_ptr的源代码在boost/shared_ptr.hpp里。先看它的私有变量:
T * px; // contained pointer
boost::detail::shared_count pn; // reference counter
多了一个引用计数器,是一个boost::detail::shared_count类型,再翻源代码boost/detail/shared_count.hpp,只看用到的三个方法:
C++:
  1. bool unique() const // nothrow
  2. {
  3. return use_count() == 1;
  4. }
  5. void swap(shared_count & r) // nothrow
  6. {
  7. sp_counted_base * tmp = r.pi_;
  8. r.pi_ = pi_;
  9. pi_ = tmp;
  10. }
  11. long use_count() const // nothrow
  12. {
  13. return pi_ != 0? pi_->use_count(): 0;
  14. }
呃,还有一个不能漏了,赋值运算符:
C++:
  1. shared_count & operator= (shared_count const & r) // nothrow
  2. {
  3. sp_counted_base * tmp = r.pi_;
  4. if( tmp != pi_ )
  5. {
  6. if( tmp != 0 ) tmp->add_ref_copy();
  7. if( pi_ != 0 ) pi_->release();
  8. pi_ = tmp;
  9. }
  10. return *this;
  11. }
再回过头去看shared_ptr的源代码:
C++:
  1. reference operator* () const // never throws
  2. {
  3. BOOST_ASSERT(px != 0);
  4. return *px;
  5. }
  6. T * operator-> () const // never throws
  7. {
  8. BOOST_ASSERT(px != 0);
  9. return px;
  10. }
  11. T * get() const // never throws
  12. {
  13. return px;
  14. }
  15. bool operator! () const // never throws
  16. {
  17. return px == 0;
  18. }
  19. bool unique() const // never throws
  20. {
  21. return pn.unique();
  22. }
  23. long use_count() const // never throws
  24. {
  25. return pn.use_count();
  26. }
  27. void swap(shared_ptr<T> & other) // never throws
  28. {
  29. std::swap(px, other.px);
  30. pn.swap(other.pn);
  31. }
  32. shared_ptr & operator=( shared_ptr && r ) // never throws
  33. {
  34. this_type( static_cast<shared_ptr &&>( r ) ).swap( *this );
  35. return *this;
  36. }

这样一切都明了了。所以,auto_ptr和shared_ptr在使用上的区别也好理解了,下面的小程序可以展示:
C++:
  1. #include <iostream>
  2. #include <memory>
  3. #include <boost/shared_ptr.hpp>
  4. using namespace boost;
  5. using std::cout;
  6. using std::endl;
  7. using std::auto_ptr;
  8. class A
  9. {
  10. public:
  11. void print()
  12. {
  13. cout<<"hello"<<endl;
  14. }
  15. };
  16. int main()
  17. {
  18. auto_ptr<A> aptr1(new A);
  19. auto_ptr<A> aptr2;
  20. aptr2 = aptr1;
  21. aptr2->print(); //Ok
  22. cout<<"pointer in aptr1 is: "<<aptr1.get()<<endl;
  23. aptr1->print(); //Wrong!
  24. A * a = new A;
  25. shared_ptr<A> sptr1(a);
  26. shared_ptr<A> sptr2(sptr1); //alright
  27. sptr2 = sptr1;
  28. sptr2->print(); //ok
  29. sptr1->print(); //ok
  30. int * b = new int;
  31. shared_ptr<int> sptr3(b);
  32. shared_ptr<int> sptr4(b); //WRONG!!
  33. return 0;
  34. }

No comments:

Post a Comment