C++ std::shared_ptr 实现原理
上周五排查了一个由于XXX模块
操作疏忽导致栈越界引发的我的模块
的智能指针Crash问题,因此稍微研究了一下,以作参考:
shared_ptr共享被管理对象,同一时刻可以有多个shared_ptr拥有对象的所有权,当最后一个shared_ptr对象销毁时,被管理对象自动销毁
shared_ptr 实现
简单来说,shared_ptr
实现包含了两部分,
- 一个指向堆上创建的对象的裸指针,
raw_ptr
- 一个指向内部隐藏的、共享的管理对象。
share_count_object
第一部分没什么好说的,第二部分是需要关注的重点:
use_count
,当前这个堆上对象被多少对象引用了,简单来说就是引用计数。weak_count
,这个管理对象被多少个智能指针共享了,简单来说就是管理对象
的引用计数。
不同指针创建的对同一个堆上对象的智能管理,并不共享管理对象,因此存在double free
的可能性
_shared_ptr
直接包含的裸指针,即raw prt
,是为了实现一般指针的->,*等操作,通过__shared_count object
间接包含的指针是为了管理对象的生命周期,回收相关资源。
换句话说,__shared_count object
内部的use_count
主要用来标记被管理对象的生命周期,weak_count
主要用来标记管理对象的生命周期。
注意区分管理和被管理。
问题原因
了解了原理,可以看出std::share_ptr
本身的raw ptr
指向了堆上通过new
创建的对象。但是其自身这个raw ptr
却会如果在不当操作上,被修改,比如栈越界操作,就会被破坏,导致产生对非法对象的访问:
int i = 5;
NSLog(@"i address is %p", &i);
XXX::XX df = XXX::XX::buildDataFrame();
NSLog(@"sp0 address is %p", &df);
int a[1] = {1};
NSLog(@"k address is %p", a);
for (int i = 0; i < 10; i++) {
a[i] = i;
}
NSLog(@"haha");
上述这段代码就会引发问题,这里XXX::XX
的具体内部设计使用了经典的RAII
,下文再表。