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

Why copy constructor is being called two times in below code?

本文关键字:两次 构造函数 复制 在下面 代码 调用 为什么      更新时间:2023-10-16

谁能解释为什么这里的复制构造函数被调用两次?

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;
}

当我运行代码输出时,输出是:

IN constr
in copy
in copy

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

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

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

这称为通过常量引用传递参数,在 C++11 之前,它基本上是将参数传递给函数的首选方式。

如果您知道您将处理作为函数参数传递的临时对象,那么 C++11 及更高版本也有按右值传递引用 - 有关更多信息,请参阅例如按值传递与按右值传递引用。

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

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

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

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&&的构造函数,但我会权衡代码重复与好处。

如果你想知道如果碰巧std::string A可以走多远,并且你想涵盖临时A的建设,请观看尼古拉·约苏蒂斯的精彩演讲。