智能指针——shared_ptr

本文详细介绍了C++智能指针shared_ptr的原理和使用,包括其引用计数机制、线程安全特性以及在多线程环境中的注意事项。示例展示了shared_ptr在多线程环境下可能导致的问题,强调了对共享资源加锁的重要性。同时,讨论了使用make_shared的好处,以及shared_ptr在unordered_map中可能导致的性能问题。

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

1. shared_ptr的定义

shared_ptr是一种 智能指针( smart pointer)。shared_ptr的作用有如内 指针,但会记录有多少个tr1::shared_ptrs共同指向一个对象。这便是所谓的 引用计数(reference counting)。一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。这在非环形数据结构中防止资源泄露很有帮助。

2. shared_ptr的数据结构及示例

shared_ptr是引用计数型智能指针,几乎所有的实现都采用在堆上放个计数器。
在这里插入图片描述
示例1

class object
{
private:
	int value;
public:
	object(int x = 0) :value(x) {}
	~object() {}
	int& Value() { return value; }
	const int& Value( ) const { return value; }
};

int main()
{
	shared_ptr<Object> apa(new object(10));
	shared_ptr<Object> apb = apa;
	return 0;
}

在这里插入图片描述
示例2

有3个shared_ptr对象apa、gx、apb。

	shared_ptr<Object> gx(new object(1));	//线程之间共享的shared_ptr对象
	shared_ptr<Object> apa;					//线程A的局部变量
	shared_ptr<Object> apb(new object(2));	//线程B的局部变量

一开始,各安其事:
在这里插入图片描述
线程A执行 apa = gx;(即read gx),以下完成了步骤1,还没来及执行步骤⒉。这时切换到了B线程。
在这里插入图片描述
同时编程B执行gx = apb;(即write gx),两个步骤一起完成了。先是步骤1:
在这里插入图片描述
再是步骤2:
在这里插入图片描述
这时Object 1 对象已经销毁,apa.mPtr成了空悬指针!
最后回到线程A,完成步骤2:
在这里插入图片描述
总结:多线程无保护地读写gx,造成了“apa是空悬指针”的后果。这正是多线程读写同一个shared_ptr对象必须加锁的原因。

3. shared_ptr的线程安全性
  1. (shared_ptr)的引用计数本身是线程安全(引用计数是原子操作)。
  2. 多个线程同时读同一个shared_ptr对象是线程安全的。
  3. 如果是多个线程对同一个shared_ptr对象进行读和写,则需要加锁。
  4. 多线程读写shared_ptr所指向的同一个对象,不管是相同的shared_ptr对象,还是不同的shared_ptr对象,也需要加锁保护。
4. 其他注意事项
  1. shared_ptr作为unordered_map的key
    如果把 shared_ptr放到unordered_set中,或者用于unordered_map 的 key,那么要小心hash table退化为链表。但是其hash_yalue是shared_ptr隐式转换为 bool的结果。也就是说,如果不自定义hash函数,那么unordered_{set/map}会退化为链表。
  2. 为什么要尽量使用make_shared()?申请被管理对象以及引用计数的内存;调用适当的构造函数初始化对象;返回一个shared_ptr。
    为了节省一次内存分配,原来shared_ptr x(new Object(10)))需要为Object对象和RefCnt各分配一次内存,现在用make_shared()的话,可以一次分配一块足够大的内存,供Object和RefCnt对象容身。不过Object的构造函数所需的参数要传给make_shared(),后者再传给Object: : Object(),这只有在C++11里通过perfect forwarding(完美转发)才能完美解决。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值