// shared_ptr虽然能和其他shared_ptr共享同一内存,但是千万不能通过原始指针持有一个即将过期的指针,即2个非共享的share_ptr指向同一个对象,未增加引用计数导对象被析构两次情形如下:
std::shared_ptr<int> p= std::make_shared<int>(1);
{
std::unique_ptr<int> q(new int(111111));// q也可以是shared_ptr
p.reset(qw.get());// p会释放掉指向'std::make_shared<int>(1)'的内存,转而控制'new int(111111)'内存,但是却和q同时共享同一内存,但是q是临时变量,在{}执行完后释放内存,导致p成为悬空指针,后续在p析构时会重新再delete这块内存,导致重复释放出错
}
所以使用第三行reset语句的前提是你确保q放弃对其资源的控制,如q.release();
以上情形同时适用于unique_ptr
处于以上情况,c++11出了一种新特性为enable_shared_from_this类用于解决上述返回共同管理的指针的解决方案
// TEMPLATE CLASS shared_ptr
// shared_ptr智能指针类模板
template<class _Ty>
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
}
// 允许从原始指针_Px显式构造
template<class _Ux>
explicit shared_ptr(_Ux *_Px)
{ // construct shared_ptr object that owns _Px
_Resetp(_Px);
}
// 参数2为 删除器类型(删除资源数据)
template<class _Ux,
class _Dx>
shared_ptr(_Ux *_Px, _Dx _Dt)
{ // construct with _Px, deleter
_Resetp(_Px, _Dt);
}
shared_ptr(nullptr_t)
{ // construct empty shared_ptr
}
template<class _Dx>
shared_ptr(nullptr_t, _Dx _Dt)
{ // construct with nullptr, deleter
_Resetp((_Ty *)0, _Dt);
}
// 参数3:分配器类型(销毁计数器对象)
template<class _Dx,
class _Alloc>
shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax)
{ // construct with nullptr, deleter, allocator
_Resetp((_Ty *)0, _Dt, _Ax);
}
template<class _Ux,
class _Dx,
class _Alloc>
shared_ptr(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
{ // construct with _Px, deleter, allocator
_Resetp(_Px, _Dt, _Ax);
}
// 从其他智能指针构造(调用基类的_Reset)
template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Right, _Ty *_Px) _NOEXCEPT
{ // construct shared_ptr object that aliases _Right
this->_Reset(_Px, _Right);
}
// copy构造函数
shared_ptr(const _Myt& _Other) _NOEXCEPT
{ // construct shared_ptr object that owns same resource as _Other
this->_Reset(_Other);
}
// enable_if的第一个参数(is_convertible<_Ty2 *, _Ty *>::value)为true时,才会内部定义type(第二个参数,这为void),否则无法通过编译
// is_convertible<_Ty2 *, _Ty *>:判断是否可以被转化 第一个参数的类型 可以转化为第二个参数的类型
// 例如对于类:如果A是基类,B是子类,那么B可以转化为A,也就是B是一种A;用is_convertible表示如下:
// std::cout << std::boolalpha; //输出格式调整,0为false,非0为true
// std::is_convertible<B, A>::value << endl;// 判断B是否可以转化为A,并返回true or false
template<class _Ty2,
class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::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<class _Ty2>
explicit shared_ptr(const weak_ptr<_Ty2>& _Other,
bool _Throw = true)
{ // construct shared_ptr object that owns resource *_Other
this->_Reset(_Other, _Throw);
}
// 从auto_ptr指针,移动构造函数
template<class _Ty2>
shared_ptr(auto_ptr<_Ty2>&& _Other)
{ // construct shared_ptr object that owns *_Other.get()
this->_Reset(_STD move(_Other));// move(左值)转为右值引用,调用基类void _Reset(auto_ptr<_Ty2>&& _Other)
}
// 类型转换
template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Other, const _Static_tag& _Tag)
{ // construct shared_ptr object for static_pointer_cast
this->_Reset(_Other, _Tag);
}
template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Other, const _Const_tag& _Tag)
{ // construct shared_ptr object for const_pointer_cast
this->_Reset(_Other, _Tag);
}
template<class _Ty2>
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指针,移动构造函数
shared_ptr(_Myt&& _Right) _NOEXCEPT
: _Mybase(_STD forward<_Myt>(_Right))// 转发右值引用属性(完全依照模板的参数的类型)
{ // construct shared_ptr object that takes resource from _Right
}
template<class _Ty2,
class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
void>::type>
shared_ptr(shared_ptr<_Ty2>&& _Right) _NOEXCEPT
: _Mybase(_STD forward<shared_ptr<_Ty2> >(_Right))
{ // construct shared_ptr object that takes resource from _Right
}
// 从unique_ptr指针,移动构造函数
template<class _Ux,
class _Dx>
shared_ptr(unique_ptr<_Ux, _Dx>&& _Right)
{ // construct from unique_ptr
_Resetp(_Right.release(), _Right.get_deleter());// 转移_Right的指针控制权给this,_Right为空
}
//赋值移动构造函数
template<class _Ux,
class _Dx>
_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<class _Ty2>
_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);
}
// 析构,引用计数-1
~shared_ptr() _NOEXCEPT
{ // release resource
this->_Decref();
}
//赋值copy构造函数
_Myt& operator=(const _Myt& _Right) _NOEXCEPT
{ // assign shared ownership of resource owned by _Right
shared_ptr(_Right).swap(*this);// shared_ptr(_Right)临时对象先递增右值的引用计数,swap交换后临时对象指向左值,即this指向了引用计数已经增1后的右值(即_Right)了,左值从之前的this指向它,编程临时对象指向它,所以到这一步时,之前左值的计数不变,等到{}代码结束后,临时对象释放,调用析构,引用计数-1,所以从代码层面印证了 =右边计数+1,左边计数-1
return (*this);
}
template<class _Ty2>
_Myt& operator=(const shared_ptr<_Ty2>& _Right) _NOEXCEPT
{ // assign shared ownership of resource owned by _Right
shared_ptr(_Right).swap(*this);
return (*this);
}
template<class _Ty2>
_Myt& operator=(auto_ptr<_Ty2>&& _Right)
{ // assign ownership of resource pointed to by _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
// 释放资源,或重新指向_Px
// 释放资源并转换为空的shared_ptr对象
void reset() _NOEXCEPT
{ // release resource and convert to empty shared_ptr object
shared_ptr().swap(*this);// 临时无名对象 和 当前对象 交换,然后无名对象在函数执行完后析构,释放资源
}
template<class _Ux>
void reset(_Ux *_Px)
{ // release, take ownership of _Px
shared_ptr(_Px).swap(*this);
}
template<class _Ux,
class _Dx>
void reset(_Ux *_Px, _Dx _Dt)
{ // release, take ownership of _Px, with deleter _Dt
shared_ptr(_Px, _Dt).swap(*this);
}
template<class _Ux,
class _Dx,
class _Alloc>
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());
}
// 是否计数为1
bool unique() const _NOEXCEPT
{ // return true if no other shared_ptr object owns this resource
return (this->use_count() == 1);
}
// 本类型到bool的转换,不允许使用参数,即if(!shared_ptr)时调用
explicit operator bool() const _NOEXCEPT
{ // test if shared_ptr object owns no resource
return (this->_Get() != 0);
}
private:
// 内部构造时调用_Resetp
template<class _Ux>
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<class _Ux,
class _Dx>
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));// 资源_Px同时交给两方管理,一处为智能指针的基类(_Ref_count_del)的成员_Ty *_Ptr;另一处为成员_Ref_count_base *_Rep(本身为计数基类)的派生类对象(这里为_Ref_count_del)的新成员_Ty * _Ptr;
_CATCH_ALL // allocation failed, delete resource
_Dt(_Px);
_RERAISE;
_CATCH_END
}
template<class _Ux,
class _Dx,
class _Alloc>
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<class _Ux>
void _Resetp0(_Ux *_Px, _Ref_count_base *_Rx)
{ // release resource and take ownership of _Px
this->_Reset0(_Px, _Rx);
_Enable_shared(_Px, _Rx); // 管理指向同一内存的指针,管理的类需继承enable_shared_from_this
}
};
// _Resetp0(_Px, new _Ref_count_del<_Ux, _Dx>(_Px, _Dt));
// 由此可见,资源由子对象_Ref_count_base的派生类对象指针_Rep管理,
// 1.当智能指针.reset()时,当前指针(含资源,引用计数n)与临时无名对象指针(没有资源,引用计数0)交换,临时无名对象(此时有资源且引用计数为n)在函数执行完后会析构;减少引用计数,
// 2.当多个指向a同一引用的智能指针放弃自己的控制权时(如.reset()或 = otherPtr时,指向a的引用计数减少)
// 上述两种情况 当引用计数减少,直至0时,_Rep(派生类)会调用自己的纯虚函数_Destroy();_Decwref();从而释放资源
/非成员函数,重载操作符,用于两智能指针间的比较(只列举几个)/
// 重载==,判断两个智能指针是否管理同一个资源
template<class _Ty1,
class _Ty2>
bool operator==(const shared_ptr<_Ty1>& _Left,
const shared_ptr<_Ty2>& _Right) _NOEXCEPT
{ // test if shared_ptr == shared_ptr
return (_Left.get() == _Right.get());
}
// 重载!=,判断两个智能指针是否管理不同一个资源
template<class _Ty1,
class _Ty2>
bool operator!=(const shared_ptr<_Ty1>& _Left,
const shared_ptr<_Ty2>& _Right) _NOEXCEPT
{ // test if shared_ptr != shared_ptr
return (!(_Left == _Right));// 调用operator==
}
// 重载<,判断参数1智能指针管理的资源地址是否小于参数2的
template<class _Ty1,
class _Ty2>
bool operator<(const shared_ptr<_Ty1>& _Left,
const shared_ptr<_Ty2>& _Right) _NOEXCEPT
{ // test if shared_ptr < shared_ptr
return (less<decltype(_Always_false<_Ty1>::value// less的模板参数为_Right.get()的类型,因为_Always_false<_Ty1>::value为false
? _Left.get() : _Right.get())>()(
_Left.get(), _Right.get()));
}
// 重载>=,判断参数1智能指针管理的资源地址是否不小于参数2的
template<class _Ty1,
class _Ty2>
bool operator>=(const shared_ptr<_Ty1>& _Left,
const shared_ptr<_Ty2>& _Right) _NOEXCEPT
{ // shared_ptr >= shared_ptr
return (!(_Left < _Right));
}
// 其余比较函数类似
// 上述比较函数为普通非成员模板函数,但是因为是两指针之间的比较,可以在类内实现,成为单参数的成员函数(p1 < p2,即调用p1.operator<(p2));
/非成员函数,重载操作符,用于智能指针和空指针间的比较(只列举几个)/
// 重载==,判断_Left智能指针管理的资源地址是否为0(没管理任何内存),if(_Left == 0)时调用,==后必须0,非0报编译错误
template<class _Ty>
bool operator==(const shared_ptr<_Ty>& _Left,
nullptr_t) _NOEXCEPT
{ // test if shared_ptr == nullptr
return (_Left.get() == (_Ty *)0);
}
// 重载==,和上述区别为if(0 == _Left)时调用,==前必须0,非0报编译错误
template<class _Ty>
bool operator==(nullptr_t,
const shared_ptr<_Ty>& _Right) _NOEXCEPT
{ // test if nullptr == shared_ptr
return ((_Ty *)0 == _Right.get());
}
// 必须和0(nullptr_t)比较,包括其他未举的例子
// 当参数为nullptr_t时,就不能写成成员模板函数了,只能写成普通模板函数,因为对于每个操作符都有两个重载函数,例如上述
// 对于==操作符的重载有两个(参数1,2互换位置),之所以这个写,是因为当有语句if(p == 0)或if (0 == p)是,都能正常调用上述两个函数。
// 而写成成员函数时,if(p == 0)可以正常调用bool operator==(nullptr_t),被解释为p.operator==(0),但是当if(0 == p ),解释为0.operator==(p)显然是不对的。
// TEMPLATE FUNCTION make_shared
template<class _Ty,class... _Types>
inline shared_ptr<_Ty> make_shared(_Types&&... _Args)
{ // make a shared_ptr
_Ref_count_obj<_Ty> *_Rx = new _Ref_count_obj<_Ty>(_STD forward<_Types>(_Args)...);
shared_ptr<_Ty> _Ret;
_Ret._Resetp0(_Rx->_Getptr(), _Rx);
return (_Ret);
}
// std::shared_ptr<int> p = std::make_shared<int>(1);