我和几位同事正在讨论当从C ++方法返回局部变量(在堆栈上分配)时会发生什么。
以下代码适用于单元测试,但我认为这只是因为单元测试很幸运,并且不会尝试重用obj使用的堆栈上的内存。
这有效吗?
static MyObject createMyObject() {
MyObject obj;
return obj;
}
答案 0 :(得分:23)
会发生复制构造函数被调用以生成本地对象的副本,这就是调用者收到的内容。
编译器可能会在名为copy elision的进程中删除副本,但这完全取决于编译器 - 您无法对其进行太多控制。
此模式能够产生您担心的问题,但前提是您将指针或引用返回到本地对象。
答案 1 :(得分:4)
obj
,然后使用对象的复制构造函数将其复制出方法/函数。
您可以通过声明obj
来使static
不在堆栈中。返回该对象也会返回一个副本,但每次调用该函数时都不会创建该对象。然后,您可以将对象作为参考返回:
static MyObject & createMyObject() {
static MyObject obj;
return obj;
}
(此处没有复制,obj
只创建一次,其地址在运行时保持不变。)
答案 2 :(得分:1)
按值返回对象,因此将调用它的复制构造函数,并返回原始对象的COPY并将其存储在调用者的堆栈中。如果此方法返回局部变量的指针(或引用),它将失败。
答案 3 :(得分:1)
返回MyObject的副本。如果MyObject具有正确复制所有内容的复制构造函数,那么这应该没问题。请注意,它可能有一个复制构造函数,即使没有明确列出一个 - 编译器定义的默认复制构造函数(成员分配所有内容)可能适用于您的目的。
答案 4 :(得分:1)
在此示例中,MyObject按值返回。这意味着它的副本被制作并传递回调用函数。 (在某些情况下the compiler can optimize the spurious copy away,但仅限于在MyObject上调用复制构造函数并将副本放在堆栈上时。)
答案 5 :(得分:1)
假设其他所有人都错过了这个问题的明显混淆来源 - static
:
您没有声明在MyObject
中创建的createMyObject
实例具有静态存储持续时间;相反,您将函数createMyObject
声明为具有内部链接。
答案 6 :(得分:1)
函数“返回本地对象”是可以的,因为编译器会将函数转换为不真正返回值。相反,它将接受一个引用 MyObject& __result
,并使用将被分配返回值的本地对象,即 obj
,来复制构造 __result
。在您的情况下,该函数将被重写为:
static void createMyObject(MyObject& __result) {
MyObject obj;
// .. process obj
// compiler generated invocation of copy constructor
__result.MyObject::Myobject( obj );
return;
}
并且每次调用 createMyObject
也将被转换以将引用绑定到现有对象。例如,对表单的调用:
MyObject a = createMyObject();
将转换为:
MyObject a; // no default constructor called here
createMyObject(a);
但是,如果您返回指向本地对象的引用或指针,编译器将无法完成转换。您将返回一个指向已销毁对象的引用或指针。
答案 7 :(得分:0)
这很好用。它将创建一个返回MyObject的临时匿名变量: