【C++】一文搞懂智能指针

【C++】一文搞懂智能指针,第1张

智能指针基本概念

头文件memory

智能指针的->运算符重载

不带引用计数的智能指针

为什么智能指针要区分带引用计数或不带引用计数呢?

因为多个智能指针指向同一份资源会引起资源的重复释放,即浅拷贝资源释放的问题,所以有的不带引用计数,但是只能有一个智能指针指向该份资源,有的带引用计数

auto_ptr

auto_ptr怎么解决浅拷贝资源多份释放的问题?

答:永远让最后一个auto_ptr指向该份资源,前边的auto_ptr被置为nullptr,图示如下:


所以auto有很多缺点:

  • 不推荐使用auto_ptr,并且在容器中最好不要用auto_ptr,因为如果容器里都是auto_ptr,如果容器要拷贝,那么之前的容器里的auto_ptr就全被置为nullptr了,说的绝对点就是:auto_ptr 不能被用在 stl 标准容器中
  • 因为auto_ptr的所有权独有,所以要防止两个auto_ptr拥有同一个对象

由于auto_ptr的种种弊端,C11舍弃掉了auto_ptr

scoped_ptr(boost库中的)

scope怎么解决浅拷贝资源多份释放的问题?

答:scope直接把拷贝构造和赋值 *** 作给删除/禁掉了,也就是语法上不让你多个指针指向同一份堆内存,不让你用一个scoped_ptr去构造另一个scoped_ptr,scope_ptr没有提供带右值引用的拷贝构造

scoped_ptr使用的比较少,不带引用计数的智能指针推荐使用unique_ptr

unique_ptr

不带引用计数的智能指针推荐使用unique_ptr

unique_ptr只让一个智能指针管理资源,unique_ptr也禁掉了拷贝构造和赋值,但是提供了带右值引用的拷贝构造和赋值重载,所以涉及到右值的拷贝构造都是可以用unique_ptr的,比如用std::move移动语义将一个指针的资源转移到新指针、作为函数返回值类型,unique_ptr相当于独占资源

unique_ptr<int> p1(new int);
unique_ptr<int> p2(p1);  //error
//但是可以这样:
unique_ptr<int> p2(std::move(p1));  //ok

template<typename T>
unique_ptr<T> getSmartPtr()
{
    unique_ptr<T> ptr(new T());
    return ptr;  //ok
}

unique_ptr<int> up = getSmartPtr<int>(); //ok

unique_ptr相比于auto_ptr的好处:

  • unique_ptr在写的时候,如果想拷贝构造成功,用户是一定要写std::move的,用意是很明显的(资源转移)
  • 而auto_ptr没有禁掉拷贝构造,却底层实现了资源的转移,用户正常使用ptr2(ptr1);,却已经把ptr1的资源转移给ptr2了,就很危险
带引用计数的智能指针shared_ptr和weak_ptr

带引用计数:多个智能指针可以管理同一个资源

带引用计数:给每一个对象资源,匹配一个引用计数

智能指针 =》引用资源的时候 =》引用计数+1

智能指针 =》不使用资源的时候 =》引用计数-1 =》!=0 不释放资源,为0释放资源

库里面的shared_ptr和weak_ptr引用计数的加减是线程安全的,因为用atomic定义了引用计数

shared_ptr是强智能指针,可以改变资源的引用计数

循环引用问题,造成new出来的资源无法释放,资源泄露

class B;
class A
{
public:
    A() { cout<<"A()"<<endl; }
    ~A() { cout<<"~A()"<<endl; }
    shared_ptr<B> ptrb;
};

class B
{
public:
    B() { cout<<"B()"<<endl; }
    ~B() { cout<<"~B()"<<endl; }
    shared_ptr<A> ptra;
};

int main()
{
    shared_ptr<A> pa(new A());
    shared_ptr<B> pb(new B());
    
    pa->ptrb = pb;
    pb->ptra = pa;
    
    cout<<pa.use_count() <<endl;  //打印引用计数
    cout<<pb.use_count() <<endl; 
}

如何解决循环引用问题?

  • 定义对象的时候,用强智能指针;引用对象的地方,使用弱智能指针
  • weak_ptr之所以可以打破循环引用,是因为:将一个 weak_ptr 绑定到一个 shared_ptr 不会改变 shared_ptr 的引用计数

weak_ptr是弱智能指针,不会改变资源的引用计数

weak_ptr =》(观察)shared_ptr =>(管理) 资源(内存)

注意:weak_ptr只是一个观察者,它并不能直接 *** 纵资源,没有重载->和*运算符,所以不能->这样输出,要用lock返回shared_ptr类型才能用->

强弱智能指针解决的另一问题:多线程访问共享对象的线程安全问题

自定义删除器

智能指针的删除器:deletor,对于不同的资源有不同的资源释放方式

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/674560.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-19
下一篇 2022-04-19

发表评论

登录后才能评论

评论列表(0条)

保存