0

我有一个包含普通构造函数和复制构造函数的类的以下简单代码

class largeObj
{
public:
    largeObj()
    {
        printf("\nNormal constructor\n");
    }

    largeObj(const largeObj& mv)
    {
        printf("\nCopy constructor\n");
    }

    ~largeObj()
    {
        printf("\nDestroying..\n");
    }

    void tryme()
    {
        printf("\nHi :)\n");
    }

};

largeObj iReturnLargeObjects()
{
    largeObj md;


    return md;
}


int main()
{

    largeObj mdd = iReturnLargeObjects();

    mdd.tryme();

    return 0;
}

输出是

普通构造函数

复制构造函数

破坏..

你好 :)

我明白了为什么。

但是如果我替换以下行

largeObj mdd = iReturnLargeObjects();

largeObj& mdd = iReturnLargeObjects();

输出是一样的,这是为什么呢?

我的意思是:在第一种情况下不应该有另一个副本(没有&)吗?这两条线有什么区别,为什么它们的行为相同?

4

2 回答 2

4
largeObj& mdd = iReturnLargeObjects();

您不能将可变的左值引用绑定到右值。这是非法的 C++,只有某些特定的编译器扩展允许。然而,问题的语义没有改变,即使这个引用是const合法的,因此赋值是合法的。

您的输出没有什么不同的原因是因为称为 RVO 的编译器优化。这种优化在 C++ 标准中明确允许,允许编译器在某些限制内跳过它认为不必要的构造对象——即使这样做会改变程序的语义,这使得它成为一种非常不寻常的优化。

底线是:不要将副作用放在复制/移动构造函数和析构函数中,因为即使程序的正确性取决于调用它们,编译器也可以消除它们。

于 2012-04-10T22:35:40.583 回答
0

你用的是什么编译器,我敢打赌这行得通,因为无论你使用什么编译器都没有在返回后将未使用的堆栈变量清零,你没有遇到段错误,因为它仍然是你的堆栈。基本上 md 留在堆栈上,您在技术上仍然可以解决。两者的区别在于

大对象 md;

是一个完整地接收变量的变量。

largeObj& mdd = iReturnLargeObjects();

是对由于惰性编译器仍然存在的变量的引用。

于 2012-04-10T23:00:22.500 回答