相比于上一代的智能指针auto_ptr来说,新进老大shared_ptr可以说近乎完美,但是通过引用计数实现的它,虽然解决了指针独占的问题,但也引来了引用成环的问题,这种问题靠它自己是没办法解决的,所以在C++11的时候将shared_ptr和weak_ptr一起引入了标准库,用来解决循环引用的问题。
class Child;
class Parent
{
public:
shared_ptr<Child> child;
Parent() { cout << "Parent" << endl; }
~Parent() { cout << "~Parent" << endl; }
void hi() { cout << "Hello" << endl; }
};
class Child
{
public:
shared_ptr<Parent> parent;
Child() { cout << "Child" << endl; }
~Child() { cout << "~Child" << endl; }
};
void fun()
{
shared_ptr<Parent> p = make_shared<Parent>();
shared_ptr<Child> c = make_shared<Child>();
p->child = c;
c->parent = p;
c->parent->hi();
}
int main()
{
fun();
return 0;
}
此时两个智能指针的引用计数都为2,但是当函数生命周期结束,引用计数结果为1,那么会出现只有构造函数没有析构函数
这里就需要引入弱引用智能指针
class Child;
class Parent
{
public:
//shared_ptr child;
std::weak_ptr<Child> child;
Parent() { cout << "Parent" << endl; }
~Parent() { cout << "~Parent" << endl; }
void hi() { cout << "Hello" << endl; }
};
class Child
{
public:
//shared_ptr parent;
std::weak_ptr<Parent> parent;
Child() { cout << "Child" << endl; }
~Child() { cout << "~Child" << endl; }
};
void fun()
{
shared_ptr<Parent> p = make_shared<Parent>();
shared_ptr<Child> c = make_shared<Child>();
p->child = c;
c->parent = p;
//c->parent->hi();
}
int main()
{
fun();
return 0;
}
在RefCnt中引入了,_weaks的计数,用来帮助解决共享智能指针的缺陷
weak_ptr的原理
weak_ptr是为了配合shared_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,也就是,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。不论是否有weak_ptr指向,一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。从这个角度看,weak_ptr更像是shared_ptr的一个助手而不是智能指针。
template<class _Ty>
class MyDeletor //可接受一切类型方案
{
public:
MyDeletor() = default;//默认构造函数
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete ptr;
}
}
};
template<class _Ty>
class MyDeletor<_Ty[]> //部分特化
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr)const
{
if (ptr != nullptr)
{
delete[] ptr;
}
}
};
template<class _Ty>
class RefCnt
{
public:
_Ty* _Ptr; //obj
std::atomic_int _Uses; //shared_ptr
std::atomic_int _Weaks; //weak_ptr
public:
RefCnt(_Ty* p):_Ptr(p),_Uses(1),_Weaks(1)
{}
~RefCnt()
{}
void _Incref()
{
_Uses += 1;
}
void _Incwref()
{
_Weaks += 1;
}
};
template<class _Ty> class my_weak_ptr;
template<class _Ty,class _Dx = MyDeletor<_Ty>>
class my_shared_ptr
{
private:
_Ty* _Ptr;
RefCnt<_Ty>* _Rep;
_Dx _mDeletor;
public:
my_shared_ptr(_Ty* p = nullptr) :_Ptr(nullptr), _Rep(nullptr)
{
if (p != NULL)
{
_Ptr = p;
_Rep = new RefCnt<_Ty>(p);
}
}
my_shared_ptr(const my_shared_ptr& _Y):_Ptr(_Y._Ptr),_Rep(_Y._Rep)
{
if (_Rep != nullptr)
{
_Rep->_Incref();//引用计数增一
}
}
my_shared_ptr(my_shared_ptr&& other)
{
other.swap(*this); //资源交换
}
my_shared_ptr& operator=(const my_shared_ptr& r)
{
if (this == &r || this->_Ptr == r._Ptr) return *this;
if (_Ptr != nullptr && --_Rep->_Uses == 0)
{
_mDeletor(_Ptr); //删除旧资源
if (--_Rep->_Weaks == 0)
{
delete _Rep; //删除计数器
}
}
_Ptr = r._Ptr;
_Rep = r._Rep;
if (_Ptr != nullptr)
{
_Rep->_Incref();//共享自加
}
return *this;
}
my_shared_ptr& operator=(my_shared_ptr&& other)
{
if (this == &other) return *this;
if (this->_Ptr != nullptr && other._Ptr != nullptr && this->_Ptr == other._Ptr)
{
this->_Rep->_Uses -= 1;
other._Ptr = nullptr;
other._Rep = nullptr;
return *this;
}
if (_Ptr != nullptr && --_Rep->_Uses == 0)
{
_mDeletor(_Ptr);
if (--_Rep->_Weaks == 0)
{
delete _Rep;
}
}
_Ptr = other._Ptr;
_Rep = other._Rep;
other._Ptr == nullptr;
other._Rep == nullptr;
return *this;
}
~my_shared_ptr()
{
if (_Rep != nullptr&& --_Rep->_Uses == 0)//uses 持有对象的生存期到期
{
_mDeletor(_Ptr); //删除对象
if (_Rep->_Weaks == 0)
{
delete _Rep; //删除计数器结构
}
}
_Ptr = nullptr;
_Rep = nullptr;
}
_Ty* get()const
{
return _Ptr;
}
_Ty& operator*()const
{
return *get();
}
_Ty* operator->()const
{
return get();
}
size_t use_count()const
{
if (_Rep == nullptr) return 0;
return _Rep->_Uses;
}
void swap(my_shared_ptr& r)
{
std::swap(_Ptr, r._Ptr);
std::swap(_Rep, r._Rep);
}
operator bool() const
{
return _Ptr != nullptr;
}
};
在上面代码中,通过新引入的_weaks;当op1进行析构,调动共享性智能指针的析构函数,调动删除器将 Object 的对象进行销毁,但是由于_weaks的计数不为1,所以不会对RefCnt引用计数器进行删除,即使 Object 资源已经释放;接着析构wp,当弱引用计数_weaks为零后才会对 RefCnt 进行释放
template<class _Ty>
class my_weak_ptr
{
private:
RefCnt<_Ty>* _Rep;
public:
my_weak_ptr():_Rep(nullptr) //不会新建RefCnt
{}
my_weak_ptr(const my_shared_ptr<_Ty>& other):_Rep(other._Rep)
{
if (_Rep != nullptr)
{
_Rep->_Incwref(); //weaks 自加
}
}
my_weak_ptr(const my_weak_ptr& other) :_Rep(other._Rep)
{
if (_Rep != nullptr)
{
_Rep->_Incwref();
}
}
my_weak_ptr(const my_weak_ptr&& other):_Rep(other._Rep)
{
other._Rep = nullptr;
}
my_weak_ptr& operator=(const my_weak_ptr& other)
{
if (this == &other && this->_Rep == other._Rep) return *this;
if (_Rep != nullptr && --_Rep->_Weaks == 0) //前置自减!!!
{
delete _Rep;
}
_Rep = other._Rep;
if (_Rep != nullptr)
{
_Rep->_Incwref();
}
return *this;
}
my_weak_ptr& operator=(my_weak_ptr&& other)
{
if (this == &other) return *this;
if (this->_Rep != nullptr && other._Rep != nullptr && this->_Rep == other._Rep)
{
other->_Rep->_Weaks -= 1;
other._Rep == nullptr; //删除other资源
return *this;
}
if (_Rep != nullptr && --_Rep->_Weaks == 0)
{
delete this._Rep;
}
this._Rep = other._Rep;
other._Rep = nullptr;
}
my_weak_ptr& operator=(const my_shared_ptr<_Ty>& other)//强指针给弱引用赋值
{
if (_Rep != nullptr && --_Rep->_Weaks == 0)
{
delete _Rep;
}
_Rep = other._Rep;
if (_Rep != nullptr)
{
_Rep->_Incwref();
}
return *this;
}//不能将强指针移动赋值给弱引用
~my_weak_ptr()
{
if (_Rep != nullptr && --_Rep->_Weaks == 0) //弱引用计数为0 {
{
delete _Rep; //删除RefCnt
}
_Rep == nullptr;
}
bool expired() const //检查被引用的对象是否删除
{
return this->_Rep->_Uses == 0;
}
my_shared_ptr<_Ty> lock()const
{
my_shared_ptr<_Ty> _Ret;
_Ret._Ptr = this->_Rep->_Ptr;
_Ret._Rep = this->_Rep;
_Ret._Rep->_Incref();
return _Ret;
}
};
我们不需要担心,当弱引用智能指针析构删除 RefCnt 的时候会造成共享智能指针的资源丢失,因为弱引用智能指针不会新建 RefCnt 并且在共享智能指针中会对weaks首先赋值为1,并且弱引用指针没有权限去释放计数器所指的资源
class Child;
class Parent
{
public:
my_weak_ptr<Child> c;
public:
Parent()
{
cout << "parent" << endl;
}
~Parent()
{
cout << "~parent" << endl;
}
void hi()const
{
cout << "hello parent" << endl;
}
};
class Child
{
public:
my_weak_ptr<Parent> p;
Child()
{
cout << "Child" << endl;
}
~Child()
{
cout << "~Child" << endl;
}
};
void fun()
{
my_shared_ptr<Parent> parent(new Parent());
my_shared_ptr<Child> child(new Child());
parent->c = child;
child->p = parent;
child->p.lock()->hi();
}
int main()
{
fun();
return 0;
}
shared_ptr child
智能指针,_Usrs 强引用计数自减后为0,继而将其所指的Child对象进行析构shared_ptr parent
智能指针,_Weaks 弱引用计数随着上一步孩子对象析构,引用计数变为1shared_ptr parent
,_Usrs自减后为0,将其所指Parent对象进行析构,并且由于_Weaks 弱引用计数也自减得0,将其 RefCnt 进行析构shared_ptr child
所指 RefCnt 中的_Weaks 也变为0,将child智能指针的 RefCnt 也进行析构