背景
使用智能指针指向class的成员变量会导致指针Segmentation fault.
复现
直接看代码https://godbolt.org/z/Tnx45jraP
#include <iostream>
#include <memory>
struct Handler
{
int num = 7;
};
int main()
{
Handler handler;
std::shared_ptr<int> ptr = nullptr;
ptr.reset(&handler.num);
std::cout<< *ptr << std::endl;
return 0;
}
运行结果
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 139
free(): invalid pointer
Program terminated with signal: SIGSEGV
7
分析
指针的值成功打印后发生错误,换成引用就没问题。
使用raw pointer int*也没问题,看来问题出在shared_ptr::reset()
方法上。
template< class Y, class Deleter, class Alloc >
void reset( Y* ptr, Deleter d, Alloc alloc );
根据定义Deleter
和Alloc
可以不传,其中Deleter
会采取默认行为free()
而智能指针所管理的handler.num
为handler
所拥有
而handler
析构时也会尝试释放成员变量num
最终导致double free问题。
解决
知道原因,可以想到如下解决方案:
- 使用raw pointer代替智能指针阻止析构发生
- 手动传入deleter方法阻止智能指针析构所指对象
这里提供第二种代码案例https://godbolt.org/z/Kfee11qqW
#include <iostream>
#include <memory>
struct Handler
{
int num = 7;
};
void D(void * p)
{
std::cout<< "This deleter does nothing." << std::endl;
}
int main()
{
Handler handler;
std::shared_ptr<int> ptr = nullptr;
ptr.reset(&handler.num, D);
std::cout<< *ptr << std::endl;
return 0;
}
参考
std::shared_ptr