#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正在这里发挥作用。但它仍然没有解释我返回参考的情况。我认为它应该始终是段错误。

有任何解释吗?

有帮助吗?

解决方案

扩展@ flyfishr64的答案

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

X s = fun();

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

X s(fun());

“缺点”你看到打印出来的是fun()中的实例。请参阅此文章: C ++中的赋值运算符了解更多信息。

其他提示

这将返回对堆栈上的对象的引用,该对象在方法返回后不存在 - 堆栈未展开,内存仍在那里,但您不应该使用它

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

当您将其更改为:

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

您现在正在返回副本。如果编译器足够聪明,它可能会这样做:

X fun() {
    return X();
}

在这种情况下, X 直接在调用者堆栈中分配,因此不需要复制。

如果是否发生段错误取决于您是否访问了无效内存。

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

在此代码中:

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

由于返回值优化允许编译器绕过创建局部变量's'并直接在返回的变量中构造X,因此不会调用复制构造函数。

您可以在此处了解有关RVO的更多信息

当你返回对这样的局部变量的引用时,你正在调用未完成的行为。

在这种情况下它恰好起作用,因为 class X 的所有函数都没有实际使用 this 指针,所以它不再有效并不重要。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top