目录
auto_ptr
unique_ptr
并发问题
循环引用问题
个人主页:传送门——>东洛的克莱斯韦克
智能指针的原理:传送门——>智能指针的原理
auto_ptr
使用方法参考官方文档
传送门——>auto_ptr文档
auto_ptr并不是一个优秀的智能指针,它的设计理念是——管理权转移。如下代码示意
auto_ptr(auto_ptr<T>& sp)
:_ptr(sp._ptr)
{
// 管理权转移
sp._ptr = nullptr;
}
旧的智能指针的会转移给新的智能指针,而旧的智能指针的会被置空。所以就有一个很严重的问题——如果对置空的智能指针做了加加减减等操作呢?如下代码示意
int main()
{
std::auto_ptr<int> sp1(new int);
std::auto_ptr<int> sp2(sp1); // 管理权转移
//sp1悬空
*sp2 = 10;
cout << *sp2 << endl;
cout << *sp1 << endl;
return 0;
}
auto_ptr是一个失败设计,很多公司明确要求不能使用auto_ptr
unique_ptr
使用方法参考官方文档
传送门——>unique_ptr文档
unique_ptr智能指针的设计理念很简单——防拷贝。也就是说一份资源只能由一个unique_ptr管理,如下代码示意
unique_ptr(const unique_ptr<T>& sp) = delete;
unique_ptr<T>& operator=(const unique_ptr<T>& sp) = delete;
shared_ptr
使用方法参考官方文档
传送门——>shared_ptr文档
不同于unique_ptr,shared_ptr的允许多个智能指针管理同一份资源。shared_ptr采用引用计数的机制来判断一个资源是否允许被销毁
shared_ptr的引用计数是额外申请了空间(并没有在类的内部),它的设计是由一个指针指向一块空间,该空间存放计数。这种设计难免会有内存碎片的问题
代码示意
shared_ptr(T* ptr = nullptr)
:_ptr(ptr)
, _pRefCount(new int(1)) //额外开辟空间
, _pmtx(new mutex)
{}
并发问题
引用计数本身是有并发问题的,关于线程,并发,锁相关知识可参考小编另一篇文章。
传送门——>线程,并发,锁
1.智能指针对象中引用计数是多个智能指针对象共享的,两个线程中智能指针的引用计数同时 ++或--,这个操作不是原子的,引用计数原来是1,++了两次,可能还是2.这样引用计数就错 乱了。会导致资源未释放或者程序崩溃的问题。所以只能指针中引用计数++、--是需要加锁 的,也就是说引用计数的操作是线程安全的。
2. 智能指针管理的对象存放在堆上,两个线程中同时去访问,会导致线程安全问题。
所以引用计数的加加减减操作是加锁的。如下代码示意
void Release()
{
_pmtx->lock();
bool flag = false;
if (--(*_pRefCount) == 0 && _ptr)
{
cout << "delete:" << _ptr << endl;
delete _ptr;
delete _pRefCount;
flag = true;
}
_pmtx->unlock();
if (flag == true)
{
delete _pmtx;
}
}
void AddRef()
{
_pmtx->lock();
++(*_pRefCount);
_pmtx->unlock();
}
循环引用问题
该问题是有类似于链表节点的结构引起的,当外部的智能指针都释放了,就拿不内部的智能指针,那么节点就不会释放
解决方案:在引用计数的场景下,把节点中的_prev和_next改成weak_ptr就可以了,weak_ptr不会增加引用计数,代码示意
struct ListNode
{
int _data;
weak_ptr<ListNode> _prev;
weak_ptr<ListNode> _next;
};