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 = #
//不允许直接将指针赋值给类
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,否则返回 false
w.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_ptr
std::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++|项目开发—智能指针回顾的主要内容,如果未能解决你的问题,请参考以下文章
(转)Delphi2009初体验 - 语言篇 - 智能指针(Smart Pointer)的实现