2.1 基本语义
share_ptr 允许多个share_ptr对象共享听一个资源,通过引用计数来管理共享资源的生命周期,当最后一个shared_ptr对象被销毁时,引用计数变为0,其管理的资源也就被释放了。
2.2 实现原理
每一个shared_ptr包含一个引用计数指针,当其copy constructor或者assignment operator执行时候,其引用计数增加1,当其析构函数执行时候,其引用计数减1,引用计数增加或者减少是原子操作,因此多线程操作是安全的,其具体实现见如下代码
template <class _Ty2>
void _Copy_construct_from(const shared_ptr<_Ty2>& _Other) noexcept {
// implement shared_ptr's (converting) copy ctor
_Other._Incref(); //引用计数+1
_Ptr = _Other._Ptr;
_Rep = _Other._Rep;
}
// construct shared_ptr object that owns same resource as _Other
shared_ptr(const shared_ptr& _Other) noexcept {
this->_Copy_construct_from(_Other);
}
// construct shared_ptr object that owns same resource as _Other
template <class _Ty2, enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
shared_ptr(const shared_ptr<_Ty2>& _Other) noexcept {
this->_Copy_construct_from(_Other);
}
//assignment operator
shared_ptr& operator=(const shared_ptr& _Right) noexcept {
shared_ptr(_Right).swap(*this);
return *this;
}
template <class _Ty2>
shared_ptr& operator=(const shared_ptr<_Ty2>& _Right) noexcept {
shared_ptr(_Right).swap(*this);
return *this;
}
// release resource
~shared_ptr() noexcept {
this->_Decref();
}
//引用计数为0时候,销毁管理对象
void _Decref() noexcept { // decrement use count
if (_MT_DECR(_Uses) == 0) {
_Destroy();
_Decwref();
}
}
2.3 shared_ptr循环引用问题
#include <iostream>
#include <memory>
using namespace std;
#pragma warning(disable:4996)
class SimpleB;
class SimpleA
{
public:
SimpleA(){ cout << "this is SimpleA constructor" << endl; }
~SimpleA(){ cout << "this is SimpleA destructor" << endl; }
void SetSimpleB(shared_ptr<SimpleB> _ptr){ _simplebPtr = _ptr; }
private:
shared_ptr<SimpleB> _simplebPtr;
};
class SimpleB
{
public:
SimpleB() { cout << "this is SimpleB constructor" << endl; }
~SimpleB() { cout << "this is SimpleB destructor" << endl; }
void SetSimpe(shared_ptr<SimpleA> _ptr){ _simplePtr = _ptr; }
private:
shared_ptr<SimpleA> _simplePtr;
};
int main(int argc, char** argv)
{
{
auto simplePtrA = make_shared<SimpleA>();
auto simplePtrB = make_shared<SimpleB>();
simplePtrA->SetSimpleB(simplePtrB);
simplePtrB->SetSimpe(simplePtrA);
cout << "simplePtrA use_count : " << simplePtrA.use_count() << endl; // simpltPtrA use_count = 2
cout << "simpltPtrB use_count : " << simplePtrB.use_count() << endl; // simpltPtrB use_count = 2
}
// simpltPtrA use_count = 1
// simpltPtrB use_count = 1
//SimpleA 和 SimpleB 内存无法释放,出现内存泄漏
return 0;
}
如上示例:当两个share_ptr对象相互持有对方时,当时simplePtrA和simplePtrB引用计数为2,当simplePtrA和simplePtrB析构时候,其引用计数为1,因此其所管理的内存无法释放,赞成内存泄露。为了防止循环引用造成的内存泄漏问题,c++提供weak_ptr,用来观察shared_ptr管理的资源是否存在,并不影响被管理资源的生命周期,如果存在,则可使用lock方法获取被管理资源的shared_ptr对象;将以上示例改成如下,则可避免内存泄漏
#include <iostream>
#include <memory>
using namespace std;
#pragma warning(disable:4996)
class SimpleB;
class SimpleA
{
public:
SimpleA(){ cout << "this is SimpleA constructor" << endl; }
~SimpleA(){ cout << "this is SimpleA destructor" << endl; }
void SetSimpleB(shared_ptr<SimpleB>& _ptr){ _simplebPtr = _ptr; }
private:
weak_ptr<SimpleB> _simplebPtr;
};
class SimpleB
{
public:
SimpleB() { cout << "this is SimpleB constructor" << endl; }
~SimpleB() { cout << "this is SimpleB destructor" << endl; }
void SetSimpe(shared_ptr<SimpleA>& _ptr){ _simplePtr = _ptr; }
private:
weak_ptr<SimpleA> _simplePtr;
};
int main(int argc, char** argv)
{
{
auto simplePtrA = make_shared<SimpleA>();
auto simplePtrB = make_shared<SimpleB>();
simplePtrA->SetSimpleB(simplePtrB);
simplePtrB->SetSimpe(simplePtrA);
cout << "simplePtrA use_count : " << simplePtrA.use_count() << endl; // simpltPtrA use_count = 1
cout << "simpltPtrB use_count : " << simplePtrB.use_count() << endl; // simpltPtrB use_count = 1
}
// simpltPtrA use_count = 0
// simpltPtrB use_count = 0
//SimpleA 和 SimpleB 内存被释放
return 0;
}