C++ & 符号和从函数接收对象

C++ ampersand receiving object from function

本文关键字:对象 函数 符号 C++      更新时间:2023-10-16

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

class largeObj
{
public:
    largeObj()
    {
        printf("nNormal constructorn");
    }
    largeObj(const largeObj& mv)
    {
        printf("nCopy constructorn");
    }
    ~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();

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

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

largeObj& mdd = iReturnLargeObjects();

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

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

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

你用的是什么编译器,我敢打赌这是有效的,因为你使用的任何编译器都不会在返回后将未使用的堆栈变量清零,你没有得到 seg 错误,因为它仍然是你的堆栈。 基本上MD被留在堆栈上,从技术上讲,您仍然可以解决。 两者之间的区别是

大Obj md;

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

largeObj& mdd = iReturnLargeObjects();

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