C++ 智能指针(三) std::shared_ptr

文章介绍了C++中的std::shared_ptr,一种使用引用计数的智能指针,解决了多个对象共享所有权的问题。推荐使用make_shared创建对象,以提高效率和异常安全性。同时,文章讨论了shared_ptr的use_count()方法来获取引用计数,以及如何自定义删除器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++ STL智能指针系列:

前言

上篇文章中,我们提到了unique_ptr,解决了一部分auto_ptr的问题,但是前面这两种指针都是基于排他所有权模式,无法被多个对象托管。为应对这个问题,shared_ptr出现了。

std::shared_ptr

shared_ptr是最常用的智能指针。shared_ptr使用了引用计数(reference counting),也就是说每引用一次,引用计数就会加一,而一个生命周期结束又会减一。等到这个计数为0时,就delete。这就防止了多次析构的问题。

下面的都是两次访问都是合法的,因为shared_ptr有引用计数,就不存在所有权的问题了:

shared_ptr<Object> pObj1(new Object());
shared_ptr<Object> pObj2 = pObj1;
cout<<pObj1->num<<endl;
cout<<pObj2->num<<endl;

shared_ptr用法

使用std::make_shared函数创建对象

官方建议使用make_shared创建对象,主要原因是:

1.创建方便
对比于传统的默认构造函数:

shared_ptr<Object> pObj(new Object());

使用make_shared更加方便

auto pObj = make_shared<Object>();

2.减少分配次数
传统方法要分配一次new Object()再分配一次shared_ptr控制块,而make_ptr直接一次分配了shared_ptr控制块。

3.异常安全
假设我现在有一个函数function,我需要传入两个shared_ptr:

void function(const shared_ptr<Object1> &pObj1, 
	const shared_ptr<Object2> &pObj2);

使用时:

function(shared_ptr<Object1>(new Object1("I'm obj1")),
	shared_ptr<Object2>(new Object2("I'm obj2")));

由于C++允许按任意顺序执行子表达式(C++17之前,所以C++17之后就不存在这个问题)。其中一个可能的执行顺序是:

    1. new Object1("I'm obj1")
    1. new Object2("I'm obj2")
    1. std::shared_ptr<Object1>
    1. std::shared_ptr<Object2>

假设在第2步抛出了异常,我们就会丢失在第一步分配的内存, 这块内存回收不了, 就导致了内存泄露。

此问题的解决方法就是使用make_shared,他只用一次分配,就不存在前面的那种情况:

function(std::make_shared<Object1>("I'm obj1"),
	std::make_shared<Object2>("I'm obj2"));

其实还有一种解决方法,就是将其拆出来,分配后再传入:

shared_ptr<Object1> pObj1(new Object1("I'm obj1"));
shared_ptr<Object2> pObj2(new Object2("I'm obj2"));
function(pObj1, pObj2);

但是这种方法明显繁琐许多,所以我们还是建议使用make_shared

Notice:
make_shared无法传入deleter,如果要使用自定义的deleter,还是只有使用默认的构造函数。

常用成员方法

其中的修改器resetswap与unique_ptr相同,shared_ptr舍弃了release方法,因为其实reset()可以直接替代release()
观察器getoperator* & operator->operator[]operator bool也都相同。此外,shared_ptr还提供了其他的观察器。

1. use_count()方法

此函数返回引用计数,可以帮助我们查看被几个shared_ptr所托管:

auto pObj1 = make_shared<Object>();
auto pObj2 = pObj1;
auto pObj3 = pObj1;
cout<<pObj1.use_count()<<endl;//pObj1,pObj2,pObj3效果都相同

输出结果:

3
2. unique()方法

这个函数C++17就弃用了,C++20移除了它,这个函数的作用是检测是否只有一个shared_ptr托管,相当于use_count()==1

自定义删除器

shared_ptr也可以自定义删除器,和unique_ptr一样。在unique_ptr我们讲了伪函数与函数作为删除器,这里我们补充一下lambda表达式作为删除器,此方法也同样适用于unique_ptr.

比如对于:

class Deleter
{
public:
	void operator() (Object * p) { 
		delete[] p; 
	}
};

shared_ptr<Object> pObj(new Object[5], Deleter());

使用lambda表达式:

shared_ptr<Object> pObj(new Object[5], [](Object* p){
	delete[] p;
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

orbitgw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值