C++|项目开发—智能指针回顾

Posted Charles梦想家

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++|项目开发—智能指针回顾相关的知识,希望对你有一定的参考价值。

智能指针        

C++的智能指针: auto_ptr, shared_ptr, weak_ptr, unique_ptr ,auto_ptr已经被c++11弃用,被更安全的shared_ptr所替代。

在C++中使用new关键字开辟的内存必须被手动delete掉,不然就会导致内存的泄漏,为了解决这种因为遗忘或者异常处理而导致内存泄漏的问题,我们就要用智能指针。智能指针的思想是在构建对象时获取我们资源的指针,接着控制对资源的访问使之在对象的生命周期内一直保持有效,在对象析构时释放指针对应的内存块。

一、auto_ptr被摒弃的原因:

1、auto_ptr在拷贝或者赋值过程中,直接剥夺原对象对内存的控制权,转交给新对象,然后再将原对象指针置为nullptr。实现了管理权转移。当我们再次去访问原对象时,程序就会报错。

2、当有两个auto_ptr指向同一个对象,当一个指针过期,另一个指针在过期就会出现两次析构一个对象,也会出现问题。

二、shared_ptr

        shared_ptr(重点):其一个共享所有权的智能指针,允许多个指针指向同一个对象。shared_ptr 利用引用计数的方式实现了对所管理的对象的所有权的分享,即允许多个 shared_ptr 共同管理同一个对象。

(a)当创建智能指针类的新对象时,初始化指针,并将引用计数设置为1;

(b)当能智能指针类对象作为另一个对象的副本时,拷贝构造函数复制副本的指向辅助类对象的指针,并增加辅助类对象对基础类对象的引用计数。

(c)使用赋值操作符对一个智能指针类对象进行赋值时,先使左操作数的引用计数减 1(指针已经指向别的地方),如果减1后引用计数为 0,则释放指针所指对象内存。然后增加右操作数所指对象的引用计数(此时操作数指向对象即右操作数指向对象);

(d)完成析构函数:调用析构函数时,析构函数先使引用计数减 1,如果减至 0 则 delete 对象。

(e)勿用一个原始指针初始化多个shared_ptr, 以造成二次释放同一内存。

例子:

     int num = 10;    shared_ptr<int>ptr1 = make_shared<int>(num);    //拷贝    shared_ptr<int>ptr2(ptr1);    //     int num2 = 20;    int* pb = &num;    //不允许直接将指针赋值给类    shared_ptr<int>ptrb = make_shared<int>(num2);    ptr2 = ptrb;//赋值    pb = ptrb.get();//获取原始指针
shared_ptr<T> sptr; //指向类型为T的空指针sptr.get(); 返回sptr中保存的指针sptr.use_cout();  返回指针共享对象的智能指针数量make_shared<T>(args); 返回一个shared_ptr,指向动态分配类型为T的对象使用args初始化对象。
std::shared_ptr<int> sptr = std::make_shared<int>(10); 引用计数为1//sp1是sp的拷贝,此操作会递增sptr指向对象的引用计数std::shared_ptr<int> sp1(sptr); std::shared_ptr<int> sp = std::make_shared<int>(5);//给sptr赋值,使它指向另一个地址,此操作会递增sp指向对象的引用计数,//递减sptr原来指向对象的引用计数sptr = sp; 

缺陷:

shard_ptr 会产生一些问题:1、引用计数可能会引起线程安全问题;2、会产生循环引用的问题(循环引用需要weak_ptr和shard_ptr搭配解决)。

三、unique_ptr

unique_ptr 独占所管理的对象。无法复制到其他 unique_ptr,无法通过值传递到函数(即不能调用拷贝构造函数和赋值运算符重载函数),也无法用于需要副本的任何标准模板库 (STL)算法。

unique_ptr在生命周期内,可以改变智能指针所指对象,如创建智能指针时通过构造函数指定、通过reset方法重新指定、通过release方法释放所有权、通过移动语义转移所有权。

{        std::unique_ptr<int> uptr(new int(10));  //绑定动态对象        //std::unique_ptr<int> uptr2 = uptr;  //不能赋值        //std::unique_ptr<int> uptr2(uptr);  //不能拷贝        std::unique_ptr<int> uptr2 = std::move(uptr); //转移所有权        uptr2.release(); //释放所有权,返回指针,并将uptr2置空    }//超过uptr的作用域,內存释放
std::unique_ptr<int> upMove = std::move(up); //转移所有权//u2被初始化为u1原来保存的指针,且u1置为空std::unique_ptr<int> u2(u1.release()); u.reset():释放u指向的对象u.reset(q):如果提供了内置指针q,令u指向这个对象,否则将u置为空std::unique_ptr<int> u(new int(10)); //reset释放了u原来指向的内存,指向u1原来保存的指针,且将u1置为空u.reset(u1.release()); 

四、weak_ptr

weak_ptr是一种弱类型(不单独使用,不具有普通指针的行为,无法重载operator*->),必须配合shard_ptr来使用,并用来解决循环引用问题

可以将shared_ptr的对象赋值给weak_ptr,并且这样并不会改变引用计数。weak_ptr主要有lock、swap、reset、expired、operator=、use_count几个函数。

例子来自:https://blog.csdn.net/K346K346/article/details/81478223

weak_ptr<T> w;     //创建空 weak_ptr,可以指向类型为 T 的对象weak_ptr<T> w(sp);  //与 shared_ptr 指向相同的对象,shared_ptr 引用计数不变。T必须能转换为 sp 指向的类型w=p;        //p 可以是 shared_ptr 或 weak_ptr,赋值后 w 与 p 共享对象w.reset();      //将 w 置空w.use_count();    //返回与 w 共享对象的 shared_ptr 的数量w.expired();    //若 w.use_count() 为 0,返回 true,否则返回 falsew.lock();      //如果 expired() 为 true,返回一个空 shared_ptr,否则返回非空 shared_ptr
std::weak_ptr<T> wp; //空weak_ptr,可以指向类型为T的对象std::weak_ptr<int> wp(new int(5)); //使用weak_ptr对象构造 std::shared_ptr<int> sp = std::make_shared<int>(6);std::weak_ptr<int> wp(sp); // 使用shared_ptr对象构造//std::shared_ptr<int> sp = std::make_shared<int>(5);//shared_ptr的对象赋值给weak_ptrstd::weak_ptr<int> wp(sp);std::cout << wp.use_count() << std::endl;if(!wp.expired()){    std::shared_ptr<int> sp2 = wp.lock();    std::cout << *sp2 << std::endl;

例子来自https://blog.csdn.net/oyb_lyj/article/details/81433323

 

 

以上是关于C++|项目开发—智能指针回顾的主要内容,如果未能解决你的问题,请参考以下文章

C++ - 指针和“智能指针”

(转)Delphi2009初体验 - 语言篇 - 智能指针(Smart Pointer)的实现

C++智能指针详解:scoped_ptr

指针辨析:悬垂指针哑指针野指针智能指针

[C++11]shared_ptr共享智能指针的初始化与使用

ReactNative 4Android源码分析二: 《JNI智能指针之实现篇》