我有一个让我大开眼界的小虫子。也许这很简单,但我完全迷失了。
我有一个基本的POD struct
:
struct Data{
bool isInvalid=false;
vec3 *vector; //vec3 is another struct with x,y,z components
Node*node;
bool isFresh;
unsigned int *form;
};
我有一个功能:
Data getData(){
Data forReturn;
//...populates the forReturn struct
cout<<forReturn.vector->x; //logs correctly a value
return forReturn;
}
cout
日志正确显示我的回复Data
已填充。但是,当我从另一个函数调用此函数时,会出现另一个故事:
Data newData=getData(); //logs as above
cout<<newData.vector->x; //is empty!!
这是怎么回事?!我的日志输出并排显示这两行,因为它们一个接一个地发生,但是发生了什么?这不是多线程的,因此变量和指针不应该在这两行之间改变!
答案 0 :(得分:4)
如果以这种方式编写,则在返回过程中复制本地数据(forReturn)。因此,以正确的方式实现数据类的复制构造至关重要(以正确的方式复制所有成员)
答案 1 :(得分:2)
除非我看到您拥有的真实代码,否则我无法确定,但我的打赌是您的程序有未定义的行为,因为您正在取消引用悬空指针。我相信在您的getData()
函数中,您要forReturn.vector
指向具有自动存储持续时间的本地对象,从getData()
返回时会被销毁,就像这样:
Data getData(){
Data forReturn;
vec3 myVector;
// ...
forReturn.vector = &myVector;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ...
cout<<forReturn.vector->x; // logs correctly a value
return forReturn;
}
在上面的例子中,我按值返回Data
对象forReturn
,这意味着隐式声明的移动构造函数(在C ++ 11中)或复制构造函数(在C ++ 03中)将是调用。
由于这些隐式生成的特殊成员函数执行成员移动或复制数据结构的成员,vector
指针被复制,这意味着我返回的是一个对象类型Data
,其vector
指针指向已超出范围的对象。
这是一颗定时炸弹。一旦该指针被解除引用,“ Boom ”。请注意,“Boom ”实际上可能是一个非常无声的爆炸 - 未定义的行为意味着任何都可能发生,包括什么。