6
#include <iostream>
using namespace std;

class A
{
    int x;

public:
    A(int c) : x(c) {}
    A(const A& a) { x = a.x; cout << "copy constructor called" << endl;}
};

class B
{
    A a;

public:
    B(int c) : a(c) {}
    B(const B& b) : a(b.a) { }
    A get_A() { return a;}
};

int main()
{
    B b(10);
    A a1 = b.get_A();

}

在上面的代码中,我预计“调用复制构造函数”消息会弹出两次,因为首先,b.get_A() 将创建一个调用复制构造函数 (1) 的临时对象,其次,它将复制其对 a1 的引用s 复制构造函数 (2) ,因此显示了两条消息。

但是,该代码实际上会产生一个“称为复制构造函数”的消息。为什么?

4

2 回答 2

10

C++ 标准允许在某些情况下省略复制构造函数。通常,这意味着对象是否将从临时变量复制构造。它可以就地建造。

在这种情况下get_A();已经返回了一个副本,变成了一个临时的。然后分配a1给该临时变量。允许编译器省略额外的副本并a1在返回值get_A().

即使复制构造函数有副作用,也可能发生这种优化。

复制省略是唯一允许的可以改变可观察到的副作用的优化形式。由于某些编译器不会在允许的所有情况下都执行复制省略,因此依赖于复制/移动构造函数和析构函数的副作用的程序是不可移植的。

于 2013-05-26T07:23:31.353 回答
3

在 C++11 中,代码可能会调用移动构造函数来移动对象而不是复制它,或者在 C++03 和 C++11 中,NRVO 形式的编译器优化可能会应用复制省略来省略复制。

请注意,后者(复制省略)取决于编译器的能力并且不能保证,而前者(移动语义)在 C++11 中得到保证。

于 2013-05-26T07:23:52.347 回答