最近在使用unique_ptr时碰到一个奇怪的问题,先看一下如下这段代码
class T
{
public:
....
int* getPayLoad() {return (int *)serial_payload.data();}
private:
std::unique_ptr<std::vector<char>> serial_payload;
};
std::unque_ptr<> read()
{
char msg[5] = {1, 2, 3, 4, 5};
auto data = std::make_unique<T>(msg, msg+5);
return std::move(data);
}
int main()
{
int * data = read()->getPayLoad();
printf("data[0] = %d", data[0]);
}
其实代码比较简单
- read函数创建了一个T的对象,T里面构造的时候创建了一个vector用来保存数据,同时私有的成员变量serial_payload保存了指向这个vector的指针;
- 然后main函数中调用的时候,首先通过read函数读取了这个T对象的指针,然后调用T对象的getPayLoad函数来获取vector的数据指针
- 然后打印这些数据
看起来很简单,然而打印出来的时候取完全不是我们想要的结果,再把main中获取的data的地址打印出来,又和T类对象中创建vector的时候地址是一样的,这是怎么回事儿呢? - read()调用完成后,返回了一个unique_ptr指针,指向T类的对象,这个时候相当于这个对象的所有权转移到了main函数中;
- 之后调用getPayLoad获取了T里面生成的vector对象指针保存到了data中
- 这句话结束后,T对象这个时候并没有一个指针拥有它的所有权了,所以内存回收机制会把这段内存给回收了,也就是T对象里面创建的vector也被回收了,因为这个时候vecotr所在的内存块也没有指针拥有所有权了。
所以实际上data这个时候是一个野指针。
最快的修改方法可以如下这样
int main()
{
auto data = read();
int* data_payload = data->getPayLoad();
}
这样data就是一个unique_ptr指针,生命周期直到main函数的调用结束为止,这个过程中read中创建的对象不会被释放。
这里也涉及编码风格的问题,后面会考虑怎样的编码规范可以避免出现这种情况!这种问题通常出了就比较难查