最近在使用unique_ptr時(shí)碰到一個(gè)奇怪的問題荆虱,先看一下如下這段代碼
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]);
}
其實(shí)代碼比較簡單
- read函數(shù)創(chuàng)建了一個(gè)T的對象俄精,T里面構(gòu)造的時(shí)候創(chuàng)建了一個(gè)vector用來保存數(shù)據(jù)羽杰,同時(shí)私有的成員變量serial_payload保存了指向這個(gè)vector的指針;
- 然后main函數(shù)中調(diào)用的時(shí)候鳞骤,首先通過read函數(shù)讀取了這個(gè)T對象的指針继效,然后調(diào)用T對象的getPayLoad函數(shù)來獲取vector的數(shù)據(jù)指針
- 然后打印這些數(shù)據(jù)
看起來很簡單,然而打印出來的時(shí)候取完全不是我們想要的結(jié)果训措,再把main中獲取的data的地址打印出來伪节,又和T類對象中創(chuàng)建vector的時(shí)候地址是一樣的,這是怎么回事兒呢隙弛? - read()調(diào)用完成后架馋,返回了一個(gè)unique_ptr指針,指向T類的對象全闷,這個(gè)時(shí)候相當(dāng)于這個(gè)對象的所有權(quán)轉(zhuǎn)移到了main函數(shù)中叉寂;
- 之后調(diào)用getPayLoad獲取了T里面生成的vector對象指針保存到了data中
- 這句話結(jié)束后,T對象這個(gè)時(shí)候并沒有一個(gè)指針擁有它的所有權(quán)了总珠,所以內(nèi)存回收機(jī)制會把這段內(nèi)存給回收了屏鳍,也就是T對象里面創(chuàng)建的vector也被回收了勘纯,因?yàn)檫@個(gè)時(shí)候vecotr所在的內(nèi)存塊也沒有指針擁有所有權(quán)了。
所以實(shí)際上data這個(gè)時(shí)候是一個(gè)野指針钓瞭。
最快的修改方法可以如下這樣
int main()
{
auto data = read();
int* data_payload = data->getPayLoad();
}
這樣data就是一個(gè)unique_ptr指針驳遵,生命周期直到main函數(shù)的調(diào)用結(jié)束為止,這個(gè)過程中read中創(chuàng)建的對象不會被釋放山涡。
這里也涉及編碼風(fēng)格的問題堤结,后面會考慮怎樣的編碼規(guī)范可以避免出現(xiàn)這種情況!這種問題通常出了就比較難查