为什么复制构造函数在下面的代码中被调用两次?

时间:2018-02-28 14:47:02

标签: c++

有人可以解释为什么复制构造函数在这里被调用两次吗?

class  A 
{
    int i;
    public:
    A(){cout<<"IN constr"<<endl;};
    A(int x):i(x) {};
     A (A &a)
     {
         cout<<"in copy"<<endl;
         i= a.i;
     }
};

class MyClass {
    A var;
public:
    MyClass(A a):var(a) {
                     }
};

int main() {

    A a1;
    MyClass m(a1);
    return 0;
}

当我运行代码时,put是:

IN constr
in copy
in copy

我可以理解有一次它将a复制到变量var中,但是当它第二次被调用时?

2 个答案:

答案 0 :(得分:8)

您正在传递构造函数参数按值,这是您的第二个副本来自的位置。如果您将构造函数签名更改为更规范的C ++,您将只获得一个副本:

MyClass(const A& a)
  : var(a)
{
}

这个被称为参数传递的是 const reference ,而前C ++ 11它基本上是将参数传递给函数的首选方式。

如果你知道你将处理作为函数参数传递的临时对象,那么C ++ 11及更高版本也有传递rvalue-reference - 参见例如Pass by value vs pass by rvalue reference了解更多信息。

答案 1 :(得分:1)

第一个副本是从a1到MyClass构造函数的参数a,第二个副本是从参数a到成员var

如果您想减少副本数量,您至少有两个选项:

将Joris提到的const引用传递给构造函数:

MyClass(A const &a) : var(a) {
}

如果可以有效地移动A,请按值a移动到成员:

MyClass(A a) : var(std::move(a)) {
}

这样,不再需要A的用户可以将其移动到新的MyClass实例中,而仍然需要A的用户可以按值传递它。

void useA(A &a);
void doSomethingWithM(MyClass & m);

void functionThatNeedsAAgain() {
    A myImportantA;
    MyClass m {myImportantA}; // copy myImportantA once
    useA(myImportantA);
    doSomethingWithM(m);
}

void functionThatDoesNotNeedAAgain() {
    A tempA;
    // no copy needed, as tempA will never be used again
    MyClass m {std::move(tempA);
    doSomethingWithM(m);
}

第三个选项是提供const A&A&&的构造函数,但我会权衡代码重复与利益。

如果您想知道如果A恰好是std::string并且您想要涵盖临时A的构建,可以采取的措施,请注意excellent talk由Nicolai Josuttis撰写。