目录
- shared_ptr
- weak_ptr
- 内存模型
- RefCnt 和 Mdel实现
- shared_ptr 实现
- weak_ptr 实现
- shared_from_this()
- 循环引用
shared_ptr
采取引用计数来表示一块内存被几个智能指针所共享,当引用计数为0时,会自动释放该内存,避免了忘记手动释放造成的内存泄露问题。采用引用计数来管理内存对象的做法是Linux内核惯用的手法。
weak_ptr
weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。同时weak_ptr 没有重载*和->,但可以使用 lock 获得一个可用的 shared_ptr 对象(引用计数会增加1)。
内存模型
RefCnt 和 Mdel实现
template<typename _Ty> | |
class Mydeletor | |
{ | |
public: | |
Mydeletor() = default; | |
void operator()(_Ty* p)const | |
{ | |
if (p != NULL) | |
{ | |
delete[]p; | |
} | |
p = NULL; | |
} | |
}; | |
template<typename _Ty> | |
class RefCnt | |
{ | |
public: | |
RefCnt(_Ty* p) :ptr(p), Uses(1), Weaks(0) | |
{ | |
cout <<"RefCnt construct"<<endl; | |
} | |
~RefCnt() {} | |
void IncUses() | |
{ | |
Uses += 1; | |
} | |
void IncWeaks() | |
{ | |
Weaks += 1; | |
} | |
protected: | |
_Ty* ptr; | |
std::atomic_int Uses; | |
std::atomic_int Weaks; | |
friend class M_shared_ptr<_Ty>; | |
friend class M_weak_ptr<_Ty>; | |
}; |
shared_ptr 实现
template<typename _Ty,typename _De> | |
class M_shared_ptr | |
{ | |
private: | |
_Ty* Ptr; | |
RefCnt<_Ty>* Ref; | |
_De mdeletor; | |
public: | |
M_shared_ptr(_Ty* p = nullptr) :Ptr(nullptr),Ref(nullptr) | |
{ | |
if (p != nullptr) | |
{ | |
Ptr = p; | |
Ref = new RefCnt<_Ty>(p); | |
} | |
} | |
M_shared_ptr(const M_shared_ptr& other):Ptr(other.Ptr),Ref(other.Ref)//拷贝构造 | |
{ | |
if (Ptr != NULL) | |
{ | |
Ref->IncUses(); | |
} | |
} | |
M_shared_ptr(const M_weak_ptr<_Ty>& other):Ptr(other.GetRef()->ptr),Ref(other.GetRef())//用weak_ptr拷贝构造 | |
{ | |
if (Ptr != NULL) | |
{ | |
Ref->IncUses(); | |
} | |
} | |
M_shared_ptr(M_shared_ptr&& other) :Ptr(other.Ptr), Ref(other.Ref)//移动构造 | |
{ | |
other.Ptr = NULL; | |
other.Ref = NULL; | |
} | |
M_shared_ptr& operator=(const M_shared_ptr& other)//赋值 | |
{ | |
if (this == &other || Ptr == other.Ptr) return *this;//自赋值,直接返回本身 | |
if (Ptr != NULL && --Ref->Uses == 0)//被赋值的智能指针对象拥有资源, | |
{ //且该对象仅被该智能指针拥有 | |
mdeletor(Ptr);//释放该对象 | |
if (--Ref->Weaks == 0)//当弱引用计数为零时 | |
{ | |
delete Ref;//析构引用计数对象 | |
Ref = NULL; | |
} | |
} | |
Ptr = other.Ptr; | |
Ref = other.Ref; | |
if (Ptr != NULL) | |
{ | |
Ref->IncUses(); | |
} | |
return *this; | |
} | |
M_shared_ptr& operator=(M_shared_ptr&& other)//移动赋值 | |
{ | |
if (this == &other) return *this; | |
if (Ptr == other.Ptr && Ptr != NULL)//当两个智能指针使用同一个对象时,且该对象不为空 | |
{ | |
other.Ptr = NULL;//去掉other的使用权 | |
other.Ref = NULL; | |
Ref->Uses -= 1;//强引用计数-1 | |
return *this; | |
} | |
if (Ptr != NULL && --Ref->Uses == 0) | |
{ | |
mdeletor(Ptr); | |
if (--Ref->Weaks == 0) | |
{ | |
delete Ref; | |
Ref = NULL; | |
} | |
} | |
Ptr = other.Ptr; | |
Ref = other.Ref; | |
other.Ptr = NULL; | |
other.Ref = NULL; | |
return *this; | |
} | |
~M_shared_ptr() | |
{ | |
if (Ptr != NULL && --Ref->Uses == 0) | |
{ | |
mdeletor(Ptr); | |
if (--Ref->Weaks == 0) | |
{ | |
delete Ref; | |
} | |
} | |
Ref = NULL; | |
} | |
_Ty* get()const | |
{ | |
return Ptr; | |
} | |
_Ty& operator*() | |
{ | |
return *get(); | |
} | |
_Ty* operator->() | |
{ | |
return get(); | |
} | |
size_t use_count()const | |
{ | |
if (Ref == NULL) return 0; | |
return Ref->Uses; | |
} | |
void swap(M_shared_ptr& other) | |
{ | |
std::swap(Ptr, other.Ptr); | |
std::swap(Ref, other.Ref); | |
} | |
operator bool()const | |
{ | |
return Ptr != NULL; | |
} | |
friend class M_weak_ptr<_Ty>; | |
}; |
weak_ptr 实现
template<typename _Ty> | |
class M_weak_ptr | |
{ | |
private: | |
RefCnt<_Ty>* wRef; | |
public: | |
size_t use_count()const | |
{ | |
if (wRef == NULL) return 0; | |
return wRef->Uses; | |
} | |
size_t weak_count()const | |
{ | |
if (wRef == NULL) return 0; | |
return wRef->Weaks; | |
} | |
RefCnt<_Ty>* GetRef() const | |
{ | |
return wRef; | |
} | |
M_weak_ptr() :wRef(NULL) {} | |
M_weak_ptr(const M_shared_ptr<_Ty>& other) :wRef(other.Ref)//共享指针构造 | |
{ | |
if (wRef!=NULL) | |
{ | |
wRef->IncWeaks(); | |
} | |
} | |
M_weak_ptr(const M_weak_ptr& other) :wRef(other.wRef)//拷贝构造 | |
{ | |
if (wRef != NULL) | |
{ | |
wRef->IncWeaks(); | |
} | |
} | |
M_weak_ptr(M_weak_ptr&& other) :wRef(other.wRef)//移动构造 | |
{ | |
other.wRef = NULL; | |
} | |
M_weak_ptr& operator=(const M_weak_ptr& other) | |
{ | |
if (this == &other||wRef==other.wRef) return *this;//自赋值或者是两个指针指向同一个对象 | |
if (this != NULL && --wRef->Weaks == 0)//是否自己独占对象 | |
{ | |
delete wRef; | |
} | |
wRef = other.wRef; | |
if (wRef != NULL) | |
{ | |
wRef->IncUses(); | |
} | |
return *this; | |
} | |
M_weak_ptr& operator=(M_weak_ptr&& other) | |
{ | |
//1 判断是否自赋值 | |
if (this == &other) return *this; | |
//2 判断是否是指向同一个对象的两个指针相互赋值 | |
if (wRef == other.wRef && wRef != NULL)//如果是 | |
{ | |
other.wRef = NULL; | |
wRef->Weaks -= 1; | |
return *this; | |
} | |
//3 两个指向不同对象的指针赋值 | |
if (this != NULL && --wRef->Weaks == 0)//是否自己独占对象 | |
{ | |
delete wRef;//如果独有 | |
} | |
wRef = other.wRef; | |
other.wRef = NULL; | |
return *this; | |
} | |
M_weak_ptr& operator=(const M_shared_ptr<_Ty>& other)//共享智能指针给弱指针赋值 | |
{ | |
if (wRef == other.Ref) return *this; | |
if (wRef != NULL && --wRef->Uses == 0) | |
{ | |
delete wRef; | |
} | |
wRef = other.Ref; | |
if (wRef != NULL) | |
{ | |
wRef->IncWeaks(); | |
} | |
return *this; | |
} | |
M_weak_ptr& operator=( M_shared_ptr<_Ty>&& other) = delete; | |
~M_weak_ptr() | |
{ | |
if (wRef != NULL && --wRef->Weaks == 0) | |
{ | |
delete wRef; | |
} | |
wRef = NULL; | |
} | |
bool expired()const//判断被引用的对象是否删除,若删除则返回真 | |
{ | |
return wRef->Uses == 0; | |
} | |
M_shared_ptr<_Ty> lock()const | |
{ | |
M_shared_ptr<_Ty> tmp; | |
tmp.Ptr = wRef->ptr; | |
tmp.Ref = wRef; | |
tmp.Ref->IncUses(); | |
return tmp; | |
} | |
}; |
shared_from_this()
std::enable_shared_from_this 能让一个对象(假设其名为 t ,且已被一个 std::shared_ptr 对象 pt 管理)安全地生成其他额外的 std::shared_ptr 实例(假设名为 pt1, pt2, … ) ,它们与 pt 共享对象 t 的所有权。
使用原因:
1.把当前类对象作为参数传给其他函数时,为什么要传递share_ptr呢?直接传递this指针不可以吗?
一个裸指针传递给调用者,谁也不知道调用者会干什么?假如调用者delete了该对象,而share_tr此时还指向该对象。
2.这样传递share_ptr可以吗?share_ptr(this)
这样会造成2个非共享的share_ptr指向一个对象,最后造成2次析构该对象。
class T需要继承enable_shared_from_this才能使用shared_from_this(),具体源码如下:
namespace boost | |
{ | |
template<class T> class enable_shared_from_this | |
{ | |
protected: | |
enable_shared_from_this() | |
{ | |
} | |
enable_shared_from_this(enable_shared_from_this const &) | |
{ | |
} | |
enable_shared_from_this & operator=(enable_shared_from_this const &) | |
{ | |
return *this; | |
} | |
~enable_shared_from_this() | |
{ | |
} | |
public: | |
shared_ptr<T> shared_from_this() | |
{ | |
shared_ptr<T> p( weak_this_ ); | |
BOOST_ASSERT( p.get() == this ); | |
return p; | |
} | |
shared_ptr<T const> shared_from_this() const | |
{ | |
shared_ptr<T const> p( weak_this_ ); | |
BOOST_ASSERT( p.get() == this ); | |
return p; | |
} | |
public: // actually private, but avoids compiler template friendship issues | |
// Note: invoked automatically by shared_ptr; do not call | |
template<class X, class Y> void _internal_accept_owner( shared_ptr<X> const * ppx, Y * py ) const | |
{ | |
if( weak_this_.expired() ) | |
{ | |
//shared_ptr通过拷贝构造一个临时的shared_ptr,然后赋值给weak_ptr | |
weak_this_ = shared_ptr<T>( *ppx, py ); | |
} | |
} | |
private: | |
mutable weak_ptr<T> weak_this_; | |
}; | |
} // namespace boost | |
template<class Y> | |
explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete | |
{ | |
boost::detail::sp_enable_shared_from_this( this, p, p ); | |
} | |
template< class X, class Y, class T > inline void sp_enable_shared_from_this( boost::shared_ptr<X> const * ppx, Y const * py, boost::enable_shared_from_this< T > const * pe ) | |
{ | |
if( pe != 0 ) | |
{ | |
//调用 enable_shared_from_this对象的函数 | |
pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) ); | |
} | |
} |
可见该类包含一个weak_ptr,并在shared_ptr构造时,将weak_ptr初始化。shared_from_this()返回一个用weak_ptr拷贝构造的shared_ptr(shared_ptr有此构造函数)。
为什么一定是weak_ptr,换成shared_ptr是否可以?
类内不能包含指向自身的shared_ptr ,否则它会无法析构。
class Demo | |
{ | |
public: | |
Demo() | |
{ | |
std::cout << "constructor" << std::endl; | |
} | |
~Demo() | |
{ | |
std::cout << "destructor" << std::endl; | |
} | |
void StoreDemo(std::shared_ptr<Demo> ptr) | |
{ | |
m_ptr = ptr; | |
} | |
private: | |
std::shared_ptr<Demo> m_ptr; | |
}; | |
int main() | |
{ | |
std::shared_ptr<Demo> d_ptr(new Demo()); | |
d_ptr->StoreDemo(d_ptr); // this line is the bug | |
return 0; | |
} |
执行以上操作后d_ptr的引用计数变成2,因此当main结束时,无法执行其析构函数。
循环引用
如果两个类互相包含指向对方的shared_ptr,就会造成循环引用。导致引用计数失效,内存无法释放。
class DemoB; | |
class DemoA | |
{ | |
public: | |
DemoA() | |
{ | |
std::cout << "DemoA()" << std::endl; | |
} | |
~DemoA() | |
{ | |
std::cout << "~DemoA()" << std::endl; | |
} | |
void Set_Ptr(std::shared_ptr<DemoB>& ptr) | |
{ | |
m_ptr_b = ptr; | |
} | |
private: | |
std::shared_ptr<DemoB> m_ptr_b; | |
}; | |
class DemoB | |
{ | |
public: | |
DemoB() | |
{ | |
std::cout << "DemoB()" << std::endl; | |
} | |
~DemoB() | |
{ | |
std::cout << "~DemoB()" << std::endl; | |
} | |
void Set_Ptr(std::shared_ptr<DemoA>& ptr) | |
{ | |
m_ptr_a = ptr; | |
} | |
private: | |
std::shared_ptr<DemoA> m_ptr_a; | |
}; | |
int main() | |
{ | |
std::shared_ptr<DemoA> ptr_a(new DemoA()); | |
std::shared_ptr<DemoB> ptr_b(new DemoB()); | |
ptr_a->Set_Ptr(ptr_b); | |
ptr_b->Set_Ptr(ptr_a); | |
std::cout << ptr_a.use_count() << " " << ptr_b.use_count() << std::endl; | |
return 0; | |
} |
这种情况下 A、B的引用计数都是2,因此无法析构。
解决该问题,需要将其中一个类的shared_ptr换成weak_ptr。