3

Can anyone explain why the copy constructor here is called two times?

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

When i run the code out put is:

IN constr
in copy
in copy

I can understand one time when it copies a into the variable var, but when it gets called second time?

Stubborn
  • 780
  • 1
  • 5
  • 20

2 Answers2

8

You are passing the constructor argument by value, which is where your second copy comes from. You'll get just one copy if you change the constructor signature to the more canonical C++:

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

That's called argument passing by const reference, and pre-C++11 it was basically the go-to way of passing arguments to functions.

If you know you will be dealing with temporary objects passed as function arguments though, then C++11 and onwards also have pass-by-rvalue-reference - see e.g. Pass by value vs pass by rvalue reference for more information.

Joris Timmermans
  • 10,814
  • 2
  • 49
  • 75
1

The first copy is from a1 to the parameter a of the MyClass constructor, the second one is from the parameter a to the member var.

If you want to reduce the number of copies, you have (at least) two options:

Pass a const reference to the constructor as mentioned by Joris:

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

If A can be efficiently moved, take a by value and move to the member:

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

That way, a user that does not need his A anymore can move it into the new MyClass instance, while a user that still needs the A can pass it by value.

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

The third option would be to provide constructors from both const A& and A&& but I would weigh the code duplication against the benefit.

If you want to know how far this can be taken if A happens to be std::string and you want to cover the construction of temporary As, watch this excellent talk by Nicolai Josuttis.

PaulR
  • 3,587
  • 14
  • 24