C++ 返回中使用了什么构造函数或运算符(C+;+;)

C++ 返回中使用了什么构造函数或运算符(C+;+;),c++,return,copy-constructor,assignment-operator,C++,Return,Copy Constructor,Assignment Operator,我运行这段代码是为了试验复制构造函数和赋值运算符 class AClass { private: int a; public: AClass (int a_) : a(a_) { cout << " constructor AClass(int) " << a << endl; } AClass(const AClass & x) : a(

我运行这段代码是为了试验复制构造函数和赋值运算符

class AClass {

    private:
        int a;

    public:
        AClass (int a_) : a(a_) {  
            cout << " constructor AClass(int) " << a << endl;
        }

        AClass(const AClass & x) : a(x.a) { 
            cout << " copy constructor AClass(const AClass &) " << a << endl;
        }

        AClass & operator=(const AClass & x) { 
                a = x.a;
                cout << " AClass& operator=(const AClass &) " << a - endl;
                return *this;
        }
};

AClass g () {
    AClass x(8);
    return x;
}

int main () {

    cout << " before AClass b = g() " << endl;
    AClass b = g();
    cout << " after" << endl;

    cout << " before AClass c(g()) " << endl;
    AClass c  (g());
    cout << " after" << endl;
}

在这种情况下,编译器可以避免复制。这被称为。

编译器可能优化了复制构造函数调用。基本上,它移动对象。

这称为“返回值优化”。如果对象是按值返回的,则允许编译器在函数返回后在调用者可用的位置构造它;在这种情况下,将不会调用复制构造函数


它还可以将其视为普通的自动变量,并在返回时复制它,因此复制构造函数必须可用。是否调用取决于编译器和优化设置,因此您不应该依赖于任一行为。在C++中,

< P>,编译器允许在几乎所有情况下删除复制构造函数的调用,即使复制构造器有副作用,例如打印出消息。作为推论,它还允许在它喜欢的几乎任何点插入对复制构造函数的调用。这使得编写程序来测试您对复制和赋值的理解有点困难,但这意味着编译器可以积极地删除现实代码中不必要的复制。

这称为复制省略。编译器可以在几乎任何情况下省略副本。最常见的情况是RVO和NRVO,这基本上导致在适当的位置构造返回值。我将演示转换

void g (char* memory) {
    new (memory) AClass(8);
}

int main () {

    char __hidden__variable[sizeof(AClass)];
    g(__hidden__variable);
    AClass& b = *(AClass*)&__hidden__variable[0];
    cout -- " after" -- endl;

    // The same process occurs for c.
}

代码具有相同的效果,但现在只存在一个AClass实例。

如果您想查看编译器将调用的构造函数,必须击败RVO。替换
g()
函数,如下所示:

int i;
AClass g () {
    if(i) {
      AClass x(8);
      return x;
    } else {
      AClass x(9);
      return x;
    }
}

请选择代码样本并按下编辑器中的
{}
按钮,而不是在问题中使用
。它在保存原始代码方面做得更好。由于您正在进行实验,如果您在
g()
中将
x
设置为非自动变量,则知道您可以强制复制可能会有所帮助,例如:
AClass*x=new AClass(8);返回(*x)。当然,编写这样的代码会让你晋升为S.S.MemoryLeak的船长。考虑到C++0x中所做的更改,我会犹豫是否进行简化。C++0x只是使移动对象的显式化成为可能。即使这样,编译器也可以完全忽略您,而不调用您的移动构造函数(这让我有点困惑)。我也不太确定这是否可行。编译器不需要在单独的内存块中构造
x
的两个可能版本。如果在同一个范围内有两个不同的变量,并且有条件地返回其中任何一个,您可能会有更好的运气。事实上,在GCC中,它确实会产生明显不同的结果,而没有进行优化。谢谢,但是如果没有完成RVO,将执行什么:复制构造函数或运算符=?我已经使private operator=和两个调用仍然编译,因此结论是将使用复制构造函数。对吗?谢谢again@ciber:通常,是的,复制构造函数用于将参数传入和传出函数。我不相信赋值运算符可以这样省略,但不要引用我的话。@Dennis不,不是。编译器永远不会调用赋值op,只会显式地由程序员调用。
int i;
AClass g () {
    if(i) {
      AClass x(8);
      return x;
    } else {
      AClass x(9);
      return x;
    }
}