【问题标题】:Why copy constructor is being called two times in below code?为什么复制构造函数在下面的代码中被调用了两次?
【发布时间】:2023-03-30 20:25:02
【问题描述】:

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

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,但是当它被第二次调用时?

【问题讨论】:

  • 第一个副本 - 按值传递给 MyClass 的构造函数的对象;第二次 - 成员变量 var 被复制初始化。
  • 为了避免一个副本,您可以让 MyClass 接受 A 的引用,而不是按值.. MyClass(A& a):var(a)

标签: c++


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

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

    如果你想减少份数,你有(至少)两种选择:

    将 const 引用传递给 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&amp;A&amp;&amp; 的构造函数,但我会权衡代码重复与收益。

    如果您想知道如果 A 恰好是 std::string 并且您想涵盖临时 As 的构建,那么可以采取多远,请观看 Nicolai Josuttis 的 excellent talk

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-22
      • 1970-01-01
      • 2020-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-28
      相关资源
      最近更新 更多