#include <iostream>
using namespace std;
class X {
public:
X() {
cout<<"Cons"<<endl;
}
X(const X& x){
cout<<"Copy"<<endl;
}
void operator=(const X& x){
cout<<"Assignment called";
}
};
X& fun() {
X s;
return s;
}
int main(){
X s = fun();
return 0;
}
此代码也会调用复制构造函数。为什么这样做?我记得第一次运行这个程序时,它会出现故障。但过了一段时间,它开始称这个副本为缺点。现在工作!!奇怪的。
但如果我替换,fun()如下:
X fun() {
X s;
return s;
}
然后复制缺点。不叫。我以为复制缺点。在这种情况下会被调用。但正如@ flyfishr64所指出的,RVO正在这里发挥作用。但它仍然没有解释我返回参考的情况。我认为它应该始终是段错误。
有任何解释吗?
答案 0 :(得分:4)
这将返回对堆栈上的对象的引用,该对象在方法返回后不存在 - 堆栈未展开,内存仍在那里,但您不应该使用它
X& fun() {
X s;
return s;
}
当您将其更改为:
X fun() {
X s;
return s;
}
您现在正在返回副本。如果编译器足够聪明,它可能会这样做:
X fun() {
return X();
}
在这种情况下,X
直接在调用者堆栈中分配,因此不需要复制。
如果是否发生段错误取决于您是否访问了无效内存。
在您的示例中,您不会访问结构中的任何值。要查看segfault,首先保留一个您带有fun()
返回的引用,将一些变量添加到结构X
中,并在从fun()
返回后调用另一个在堆栈内部分配内存的方法(这应该覆盖X
中fun
使用的原始内存,并将一些值存储在堆栈中(最好是0)。在第二种方法返回后,尝试使用从X
返回的原始引用打印fun
中的值...
答案 1 :(得分:2)
在此代码中:
X fun() {
X s;
return s;
}
由于返回值优化允许编译器绕过创建局部变量's'并直接在返回的变量中构造X,因此不会调用复制构造函数。
您可以阅读有关RVO here
的更多信息答案 2 :(得分:2)
扩展@ flyfishr64的答案
这里调用了复制构造函数,因为:
X s = fun();
是初始化。您正在使用fun()来构造对象,而不是调用默认构造函数。它相当于:
X s(fun());
你看到打印出的“缺点”是fun()中的实例。请参阅此文章:Assignment operator in C++了解更多信息。
答案 3 :(得分:0)
当你返回对这样的局部变量的引用时,你正在调用未完成的行为。
在这种情况下它恰好起作用,因为class X
的所有函数都没有实际使用this
指针,所以它不再有效并不重要。