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;

其它操作皆是围绕这个进行的,你自己猜都能猜到,看看吧,构造函数中的一个:
[cpp]
explicit
auto_ptr(element_type p = 0) throw() : _M_ptr(p) { }
[/cpp]
析构函数:
[cpp]
~auto_ptr() { delete _M_ptr; }
[/cpp]
重载的赋值运算符:
[cpp]
template
auto_ptr&
operator=(auto_ptr& a) throw()
{
reset(
a.release());
return
this;
}
[/cpp]
调用了自己的reset和release方法,按住不表,下面会介绍。重载的提领运算符:
[cpp]
element_type&
operator() const throw()
{
_GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
return
_M_ptr;
}
[/cpp]

成员运算符:
[cpp]
element_type*
operator->() const throw()
{
_GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
return _M_ptr;
}
[/cpp]

get()方法:

[cpp]
element_type*
get() const throw() { return _M_ptr; }
[/cpp]

release()方法:
[cpp]
element_type
release() throw()
{
element_type
tmp = _M_ptr;
_M_ptr = 0;
return
tmp;
}
[/cpp]

reset()方法:
[cpp]
void
reset(element_type* p = 0) throw()
{
if (
p != _M_ptr)
{
delete _M_ptr;
_M_ptr = __p;
}
}
[/cpp]

这些应该没什么难理解的,可能除了那个成员运算符,只说一句: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,只看用到的三个方法:
[cpp]
bool unique() const // nothrow
{
return use_count() == 1;
}

void swap(shared_count & r) // nothrow
{
    sp_counted_base * tmp = r.pi_;
    r.pi_ = pi_;
    pi_ = tmp;
}

long use_count() const // nothrow
{
    return pi_ != 0? pi_->use_count(): 0;
}

[/cpp]
呃,还有一个不能漏了,赋值运算符:
[cpp]
sharedcount & operator= (shared_count const & r) // nothrow
{
sp_counted_base * tmp = r.pi
;

    if( tmp != pi_ )
    {
        if( tmp != 0 ) tmp->add_ref_copy();
        if( pi_ != 0 ) pi_->release();
        pi_ = tmp;
    }

    return *this;
}

[/cpp]
再回过头去看shared_ptr的源代码:
[cpp]
reference operator () const // never throws
{
BOOST_ASSERT(px != 0);
return
px;
}

T * operator-> () const // never throws
{
    BOOST_ASSERT(px != 0);
    return px;
}

T * get() const // never throws
{
    return px;
}

bool operator! () const // never throws
{
    return px == 0;
}

bool unique() const // never throws
{
    return pn.unique();
}

long use_count() const // never throws
{
    return pn.use_count();
}

void swap(shared_ptr & other) // never throws
{
    std::swap(px, other.px);
    pn.swap(other.pn);
}

shared_ptr & operator=( shared_ptr && r ) // never throws
{
    this_type( static_cast( r ) ).swap( *this );
    return *this;
}

[/cpp]

这样一切都明了了。所以,auto_ptr和shared_ptr在使用上的区别也好理解了,下面的小程序可以展示:

[cpp]

include

include

include

using namespace boost;
using std::cout;
using std::endl;
using std::auto_ptr;

class A
{
public:
void print()
{
cout<<"hello"<<endl;
}
};

int main()
{
auto_ptr aptr1(new A);
auto_ptr
aptr2;

aptr2 = aptr1;
aptr2-&gt;print(); //Ok
cout&lt;&lt;&quot;pointer in aptr1 is: &quot;&lt;&lt;aptr1.get()&lt;print(); //Wrong!

A * a = new A;
shared_ptr<a> sptr1(a);
shared_ptr<a> sptr2(sptr1); //alright
sptr2 = sptr1;
sptr2-&gt;print(); //ok
sptr1-&gt;print(); //ok

int * b = new int;
shared_ptr sptr3(b);
shared_ptr sptr4(b); //WRONG!!

return 0;

}
[/cpp]