C++里面的智能指针包括auto_ptr, shared_ptr, unique_ptr, weak_ptr四种。
auto_ptr
template
class auto_ptr
{ // wrap an object pointer to ensure destruction
public:
typedef auto_ptr<_Ty> _Myt;
typedef _Ty element_type;
explicit auto_ptr(_Ty *_Ptr = 0) _THROW0()
: _Myptr(_Ptr)
{ // construct from object pointer
}
auto_ptr(_Myt& _Right) _THROW0()
: _Myptr(_Right.release())
{ // construct by assuming pointer from _Right auto_ptr
}
auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0()
{ // construct by assuming pointer from _Right auto_ptr_ref
_Ty *_Ptr = _Right._Ref;
_Right._Ref = 0; // release old
_Myptr = _Ptr; // reset this
}
template
operator auto_ptr<_Other>() _THROW0()
{ // convert to compatible auto_ptr
return (auto_ptr<_Other>(*this));
}
template
operator auto_ptr_ref<_Other>() _THROW0()
{ // convert to compatible auto_ptr_ref
_Other *_Cvtptr = _Myptr; // test implicit conversion
auto_ptr_ref<_Other> _Ans(_Cvtptr);
_Myptr = 0; // pass ownership to auto_ptr_ref
return (_Ans);
}
template
_Myt& operator=(auto_ptr<_Other>& _Right) _THROW0()
{ // assign compatible _Right (assume pointer)
reset(_Right.release());
return (*this);
}
template
auto_ptr(auto_ptr<_Other>& _Right) _THROW0()
: _Myptr(_Right.release())
{ // construct by assuming pointer from _Right
}
_Myt& operator=(_Myt& _Right) _THROW0()
{ // assign compatible _Right (assume pointer)
reset(_Right.release());
return (*this);
}
_Myt& operator=(auto_ptr_ref<_Ty> _Right) _THROW0()
{ // assign compatible _Right._Ref (assume pointer)
_Ty *_Ptr = _Right._Ref;
_Right._Ref = 0; // release old
reset(_Ptr); // set new
return (*this);
}
~auto_ptr() _NOEXCEPT
{ // destroy the object
delete _Myptr;
}
_Ty& operator*() const _THROW0()
{ // return designated value
#if _ITERATOR_DEBUG_LEVEL == 2
if (_Myptr == 0)
_DEBUG_ERROR("auto_ptr not dereferencable");
#endif /* _ITERATOR_DEBUG_LEVEL == 2 */
return (*get());
}
_Ty *operator->() const _THROW0()
{ // return pointer to class object
#if _ITERATOR_DEBUG_LEVEL == 2
if (_Myptr == 0)
_DEBUG_ERROR("auto_ptr not dereferencable");
#endif /* _ITERATOR_DEBUG_LEVEL == 2 */
return (get());
}
_Ty *get() const _THROW0()
{ // return wrapped pointer
return (_Myptr);
}
_Ty *release() _THROW0()
{ // return wrapped pointer and give up ownership
_Ty *_Tmp = _Myptr;
_Myptr = 0;
return (_Tmp);
}
void reset(_Ty *_Ptr = 0)
{ // destroy designated object and store new pointer
if (_Ptr != _Myptr)
delete _Myptr;
_Myptr = _Ptr;
}
private:
_Ty *_Myptr; // the wrapped object pointer
};
auto_ptr的拷贝构造函数, 拷贝赋值函数用得都是非const的引用类型, 我们可以修改源对象。例如:
std::auto_ptr my_memory(new Simple(1));
std::auto_ptr my_memory2; // 创建一个新的 my_memory2 对象
my_memory2 = my_memory; // 复制旧的 my_memory 给 my_memory2
my_memory2->PrintSomething(); // 输出信息,复制成功
my_memory->PrintSomething(); // 崩溃
当使用=号赋值操作时, my_memory2完全剥夺了my_memory的内存管理所有权, 导致my_memory悬空, 最后使用时崩溃。
std::auto_ptr 的 release() 函数只是让出内存所有权,这显然也不符合 C++ 编程思想。
总结:std::auto_ptr 可用来管理单个对象的对内存,但是,请注意如下几点:
(1) 尽量不要使用“operator=”。如果使用了,请不要再使用先前对象。
(2) 记住 release() 函数不会释放对象,仅仅归还所有权。
(3) std::auto_ptr 最好不要当成参数传递(读者可以自行写代码确定为什么不能)。
(4) 由于 std::auto_ptr 的“operator=”问题,有其管理的对象不能放入 std::vector 等容器中。
unique_ptr
template // = default_delete<_Ty>
class unique_ptr
: private _Unique_ptr_base<_Ty, _Dx,
is_empty<_Dx>::value
|| is_same, _Dx>::value>
{ // non-copyable pointer to an object
public:
typedef unique_ptr<_Ty, _Dx> _Myt;
typedef _Unique_ptr_base<_Ty, _Dx,
is_empty<_Dx>::value
|| is_same, _Dx>::value> _Mybase;
typedef typename _Mybase::pointer pointer;
typedef _Ty element_type;
typedef _Dx deleter_type;
using _Mybase::get_deleter;
unique_ptr() _NOEXCEPT
: _Mybase(pointer())
{ // default construct
static_assert(!is_pointer<_Dx>::value,
"unique_ptr constructed with null deleter pointer");
}
unique_ptr(nullptr_t) _NOEXCEPT
: _Mybase(pointer())
{ // null pointer construct
static_assert(!is_pointer<_Dx>::value,
"unique_ptr constructed with null deleter pointer");
}
_Myt& operator=(nullptr_t) _NOEXCEPT
{ // assign a null pointer
reset();
return (*this);
}
explicit unique_ptr(pointer _Ptr) _NOEXCEPT
: _Mybase(_Ptr)
{ // construct with pointer
static_assert(!is_pointer<_Dx>::value,
"unique_ptr constructed with null deleter pointer");
}
unique_ptr(pointer _Ptr,
typename _If::value, _Dx,
const typename remove_reference<_Dx>::type&>::type _Dt) _NOEXCEPT
: _Mybase(_Ptr, _Dt)
{ // construct with pointer and (maybe const) deleter&
}
unique_ptr(pointer _Ptr,
typename remove_reference<_Dx>::type&& _Dt) _NOEXCEPT
: _Mybase(_Ptr, _STD move(_Dt))
{ // construct by moving deleter
static_assert(!is_reference<_Dx>::value,
"unique_ptr constructed with reference to rvalue deleter");
}
unique_ptr(unique_ptr&& _Right) _NOEXCEPT
: _Mybase(_Right.release(),
_STD forward<_Dx>(_Right.get_deleter()))
{ // construct by moving _Right
}
template::value
&& is_convertible::pointer,
pointer>::value
&& ((is_reference<_Dx>::value && is_same<_Dx, _Dx2>::value)
|| (!is_reference<_Dx>::value
&& is_convertible<_Dx2, _Dx>::value)),
void>::type>
unique_ptr(unique_ptr<_Ty2, _Dx2>&& _Right) _NOEXCEPT
: _Mybase(_Right.release(),
_STD forward<_Dx2>(_Right.get_deleter()))
{ // construct by moving _Right
}
template::value
&& is_same<_Dx, default_delete<_Ty> >::value,
void>::type>
unique_ptr(auto_ptr<_Ty2>&& _Right) _NOEXCEPT
: _Mybase(_Right.release())
{ // construct by moving _Right
}
template
typename enable_if::value
&& is_convertible::pointer,
pointer>::value,
_Myt&>::type
operator=(unique_ptr<_Ty2, _Dx2>&& _Right) _NOEXCEPT
{ // assign by moving _Right
reset(_Right.release());
this->get_deleter() = _STD forward<_Dx2>(_Right.get_deleter());
return (*this);
}
_Myt& operator=(_Myt&& _Right) _NOEXCEPT
{ // assign by moving _Right
if (this != &_Right)
{ // different, do the move
reset(_Right.release());
this->get_deleter() = _STD forward<_Dx>(_Right.get_deleter());
}
return (*this);
}
void swap(_Myt& _Right) _NOEXCEPT
{ // swap elements
_Swap_adl(this->_Myptr, _Right._Myptr);
_Swap_adl(this->get_deleter(),
_Right.get_deleter());
}
~unique_ptr() _NOEXCEPT
{ // destroy the object
if (this->_Myptr != pointer())
this->get_deleter()(this->_Myptr);
}
typename add_reference<_Ty>::type operator*() const
{ // return reference to object
return (*this->_Myptr);
}
pointer operator->() const _NOEXCEPT
{ // return pointer to class object
return (_STD pointer_traits::pointer_to(**this));
}
pointer get() const _NOEXCEPT
{ // return pointer to object
return (this->_Myptr);
}
explicit operator bool() const _NOEXCEPT
{ // test for non-null pointer
return (this->_Myptr != pointer());
}
pointer release() _NOEXCEPT
{ // yield ownership of pointer
pointer _Ans = this->_Myptr;
this->_Myptr = pointer();
return (_Ans);
}
void reset(pointer _Ptr = pointer()) _NOEXCEPT
{ // establish new pointer
pointer _Old = this->_Myptr;
this->_Myptr = _Ptr;
if (_Old != pointer())
this->get_deleter()(_Old);
}
unique_ptr(const _Myt&) = delete;
_Myt& operator=(const _Myt&) = delete;
};
unique_ptr禁止了拷贝和赋值操作, 一个unique_ptr拥有它指向的对象。
release函数返回unique_ptr当前保存的指针并将其置为空,reset函数接受一个可选的指针参数, 令unique_ptr重新指向给定的指针。
shared_ptr
template
class shared_ptr
: public _Ptr_base<_Ty>
{ // class for reference counted resource management
public:
typedef shared_ptr<_Ty> _Myt;
typedef _Ptr_base<_Ty> _Mybase;
shared_ptr() _NOEXCEPT
{ // construct empty shared_ptr
}
template
explicit shared_ptr(_Ux *_Px)
{ // construct shared_ptr object that owns _Px
_Resetp(_Px);
}
template
shared_ptr(_Ux *_Px, _Dx _Dt)
{ // construct with _Px, deleter
_Resetp(_Px, _Dt);
}
shared_ptr(nullptr_t)
{ // construct empty shared_ptr
}
template
shared_ptr(nullptr_t, _Dx _Dt)
{ // construct with nullptr, deleter
_Resetp((_Ty *)0, _Dt);
}
template
shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax)
{ // construct with nullptr, deleter, allocator
_Resetp((_Ty *)0, _Dt, _Ax);
}
template
shared_ptr(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
{ // construct with _Px, deleter, allocator
_Resetp(_Px, _Dt, _Ax);
}
template
shared_ptr(const shared_ptr<_Ty2>& _Right, _Ty *_Px) _NOEXCEPT
{ // construct shared_ptr object that aliases _Right
this->_Reset(_Px, _Right);
}
shared_ptr(const _Myt& _Other) _NOEXCEPT
{ // construct shared_ptr object that owns same resource as _Other
this->_Reset(_Other);
}
template::value,
void>::type>
shared_ptr(const shared_ptr<_Ty2>& _Other) _NOEXCEPT
{ // construct shared_ptr object that owns same resource as _Other
this->_Reset(_Other);
}
template
explicit shared_ptr(const weak_ptr<_Ty2>& _Other,
bool _Throw = true)
{ // construct shared_ptr object that owns resource *_Other
this->_Reset(_Other, _Throw);
}
template
shared_ptr(auto_ptr<_Ty2>&& _Other)
{ // construct shared_ptr object that owns *_Other.get()
this->_Reset(_STD move(_Other));
}
template
shared_ptr(const shared_ptr<_Ty2>& _Other, const _Static_tag& _Tag)
{ // construct shared_ptr object for static_pointer_cast
this->_Reset(_Other, _Tag);
}
template
shared_ptr(const shared_ptr<_Ty2>& _Other, const _Const_tag& _Tag)
{ // construct shared_ptr object for const_pointer_cast
this->_Reset(_Other, _Tag);
}
template
shared_ptr(const shared_ptr<_Ty2>& _Other, const _Dynamic_tag& _Tag)
{ // construct shared_ptr object for dynamic_pointer_cast
this->_Reset(_Other, _Tag);
}
shared_ptr(_Myt&& _Right) _NOEXCEPT
: _Mybase(_STD forward<_Myt>(_Right))
{ // construct shared_ptr object that takes resource from _Right
}
template::value,
void>::type>
shared_ptr(shared_ptr<_Ty2>&& _Right) _NOEXCEPT
: _Mybase(_STD forward >(_Right))
{ // construct shared_ptr object that takes resource from _Right
}
template
shared_ptr(unique_ptr<_Ux, _Dx>&& _Right)
{ // construct from unique_ptr
_Resetp(_Right.release(), _Right.get_deleter());
}
template
_Myt& operator=(unique_ptr<_Ux, _Dx>&& _Right)
{ // move from unique_ptr
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
_Myt& operator=(_Myt&& _Right) _NOEXCEPT
{ // construct shared_ptr object that takes resource from _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
template
_Myt& operator=(shared_ptr<_Ty2>&& _Right) _NOEXCEPT
{ // construct shared_ptr object that takes resource from _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
~shared_ptr() _NOEXCEPT
{ // release resource
this->_Decref();
}
_Myt& operator=(const _Myt& _Right) _NOEXCEPT
{ // assign shared ownership of resource owned by _Right
shared_ptr(_Right).swap(*this);
return (*this);
}
template
_Myt& operator=(const shared_ptr<_Ty2>& _Right) _NOEXCEPT
{ // assign shared ownership of resource owned by _Right
shared_ptr(_Right).swap(*this);
return (*this);
}
template
_Myt& operator=(auto_ptr<_Ty2>&& _Right)
{ // assign ownership of resource pointed to by _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
void reset() _NOEXCEPT
{ // release resource and convert to empty shared_ptr object
shared_ptr().swap(*this);
}
template
void reset(_Ux *_Px)
{ // release, take ownership of _Px
shared_ptr(_Px).swap(*this);
}
template
void reset(_Ux *_Px, _Dx _Dt)
{ // release, take ownership of _Px, with deleter _Dt
shared_ptr(_Px, _Dt).swap(*this);
}
template
void reset(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
{ // release, take ownership of _Px, with deleter _Dt, allocator _Ax
shared_ptr(_Px, _Dt, _Ax).swap(*this);
}
void swap(_Myt& _Other) _NOEXCEPT
{ // swap pointers
this->_Swap(_Other);
}
_Ty *get() const _NOEXCEPT
{ // return pointer to resource
return (this->_Get());
}
typename add_reference<_Ty>::type operator*() const _NOEXCEPT
{ // return reference to resource
return (*this->_Get());
}
_Ty *operator->() const _NOEXCEPT
{ // return pointer to resource
return (this->_Get());
}
bool unique() const _NOEXCEPT
{ // return true if no other shared_ptr object owns this resource
return (this->use_count() == 1);
}
explicit operator bool() const _NOEXCEPT
{ // test if shared_ptr object owns no resource
return (this->_Get() != 0);
}
private:
template
void _Resetp(_Ux *_Px)
{ // release, take ownership of _Px
_TRY_BEGIN // allocate control block and reset
_Resetp0(_Px, new _Ref_count<_Ux>(_Px));
_CATCH_ALL // allocation failed, delete resource
delete _Px;
_RERAISE;
_CATCH_END
}
template
void _Resetp(_Ux *_Px, _Dx _Dt)
{ // release, take ownership of _Px, deleter _Dt
_TRY_BEGIN // allocate control block and reset
_Resetp0(_Px, new _Ref_count_del<_Ux, _Dx>(_Px, _Dt));
_CATCH_ALL // allocation failed, delete resource
_Dt(_Px);
_RERAISE;
_CATCH_END
}
template
void _Resetp(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
{ // release, take ownership of _Px, deleter _Dt, allocator _Ax
typedef _Ref_count_del_alloc<_Ux, _Dx, _Alloc> _Refd;
typename _Alloc::template rebind<_Refd>::other _Al = _Ax;
_TRY_BEGIN // allocate control block and reset
_Refd *_Ptr = _Al.allocate(1);
::new (_Ptr) _Refd(_Px, _Dt, _Al);
_Resetp0(_Px, _Ptr);
_CATCH_ALL // allocation failed, delete resource
_Dt(_Px);
_RERAISE;
_CATCH_END
}
public:
template
void _Resetp0(_Ux *_Px, _Ref_count_base *_Rx)
{ // release resource and take ownership of _Px
this->_Reset0(_Px, _Rx);
_Enable_shared(_Px, _Rx);
}
};
weak_ptr
// TEMPLATE CLASS weak_ptr
template
class weak_ptr
: public _Ptr_base<_Ty>
{ // class for pointer to reference counted resource
public:
weak_ptr() _NOEXCEPT
{ // construct empty weak_ptr object
}
weak_ptr(const weak_ptr& _Other) _NOEXCEPT
{ // construct weak_ptr object for resource pointed to by _Other
this->_Resetw(_Other);
}
template::value,
void>::type>
weak_ptr(const shared_ptr<_Ty2>& _Other) _NOEXCEPT
{ // construct weak_ptr object for resource owned by _Other
this->_Resetw(_Other);
}
template::value,
void>::type>
weak_ptr(const weak_ptr<_Ty2>& _Other) _NOEXCEPT
{ // construct weak_ptr object for resource pointed to by _Other
this->_Resetw(_Other.lock());
}
~weak_ptr() _NOEXCEPT
{ // release resource
this->_Decwref();
}
weak_ptr& operator=(const weak_ptr& _Right) _NOEXCEPT
{ // assign from _Right
this->_Resetw(_Right);
return (*this);
}
template
weak_ptr& operator=(const weak_ptr<_Ty2>& _Right) _NOEXCEPT
{ // assign from _Right
this->_Resetw(_Right.lock());
return (*this);
}
template
weak_ptr& operator=(const shared_ptr<_Ty2>& _Right) _NOEXCEPT
{ // assign from _Right
this->_Resetw(_Right);
return (*this);
}
void reset() _NOEXCEPT
{ // release resource, convert to null weak_ptr object
this->_Resetw();
}
void swap(weak_ptr& _Other) _NOEXCEPT
{ // swap pointers
this->_Swap(_Other);
}
bool expired() const _NOEXCEPT
{ // return true if resource no longer exists
return (this->_Expired());
}
shared_ptr<_Ty> lock() const _NOEXCEPT
{ // convert to shared_ptr
return (shared_ptr<_Ty>(*this, false));
}
};
weak_ptr被设计为与shared_ptr共同工作,可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。同样,在weak_ptr析构时也不会导致引用计数的减少,它只是一个静静地观察者。weak_ptr没有重载operator*和->,这是特意的,因为它不共享指针,不能操作资源,这是它弱的原因。但它可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象,从而操作资源。
weak_ptr用于解决”引用计数”模型循环依赖问题,weak_ptr指向一个对象,并不增减该对象的引用计数器。weak_ptr用于配合shared_ptr使用,并不影响动态对象的生命周期,即其存在与否并不影响对象的引用计数器。weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象。weak_ptr提供了expired()与lock()成员函数,前者用于判断weak_ptr指向的对象是否已被销毁,后者返回其所指对象的shared_ptr智能指针(对象销毁时返回”空”shared_ptr)。