g ++中奇怪的C++构造函数/拷贝构造函数问题

问题描述:

#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; 
} 

这段代码也调用了拷贝构造函数。为什么这个工作?我记得我第一次运行这个程序时,它陷入了故障。但过了一段时间,它开始称这个副本缺点。现在工作!奇怪的。g ++中奇怪的C++构造函数/拷贝构造函数问题

但是如果我更换,乐趣()如下:

X fun() { 
     X s; 
     return s; 
} 

然后复制利弊。不叫。我认为副本缺点。在这种情况下会被调用。但正如@ flyfishr64指出的那样,RVO即将在这里发挥作用。但它仍不能解释我返回参考的情况。我认为它应该总是段错误。

任何解释?

+0

你不能只说“但过了一段时间,它开始称这个副本缺点,现在工作!!” - 你一定改变了一些东西。 – Smashery 2009-11-27 04:33:08

+0

没有。我做的唯一的事情是添加1 cout,然后删除它。 – user855 2009-11-27 04:35:17

+0

很有可能。因为当我尝试以下时,复制构造函数未被调用。 X&fun(){X s;返回s; } int main(){X&x = fun();返回0; } 但是用这个理论,是不是不意味着返回局部变量的引用总是有效的?因为如果我在主窗口中执行X s = fun(),那么拷贝构造函数无论如何都会被调用? – user855 2009-11-27 04:45:40

为了扩大对@ flyfishr64的回答

复制构造函数调用这里,因为这:

X s = fun(); 

是初始化。您正在使用fun()来构造对象,而不是调用默认的构造函数。它相当于:

X s(fun()); 

您看到打印出的“缺点”是针对fun()中的实例。看到这篇文章:Assignment operator in C++了解更多。

在此代码:

X fun() { 
     X s; 
     return s; 
} 

拷贝构造函数是没有得到所谓,因为返回值优化,让编译器旁路创建本地变量“s”和直接在返回的变量构建X 。

你可以阅读更多关于RVO here

这将返回引用堆栈对象不一旦方法返回存在 - 堆栈unwinded,记忆依然存在,但如果把它修改成你不应该使用它

X& fun() { 
     X s; 
     return s; 
} 

X fun() { 
     X s; 
     return s; 
} 

您现在正在返回副本。如果编译器非常聪明,它可能会做:

X fun() { 
    return X(); 
} 

在这种情况下,X在来电直接分配的堆栈,因此不需要该副本。

如果它segfault或不取决于如果您访问无效的内存。

在您的示例中,您不访问结构中的任何值。要查看段错误,请首先保留一个引用,您返回的fun()将一些变量添加到结构X中,并在从fun()返回后调用另一种在内部分配堆内存的方法(这应该覆盖在fun中使用的原始内存)堆栈中的值(最好是0)。在此第二种方法返回后,尝试使用从fun返回的原始参考打印出X的值...

当您返回对此类局部变量的引用时,您正在调用未定义的行为。

它恰好在这种情况下工作,因为class X的函数都没有使用this指针,所以无关紧要,它不再有效。

+0

仅仅返回这样的引用调用UB?你有参考吗? – 2010-01-28 13:55:48