Daksh Gupta
Daksh Gupta

Reputation: 7804

Why Copy constructor is called along with Move Constructor?

This problem seems strange but I've checked with multiple compilers. In my code, I have a Move Constructor and a copy constructor as

class A {
    int val;
public:
    A(int var) : val(var)  {
    }
    A( A && a1) {
        cout<<"M Value -> "<<a1.val<<endl;
        cout<<"Move Cons..."<<endl;
     }
    A(const A & a1) {
        cout<<"Copy Cons.."<<endl;
        cout<<"Value -> "<<a1.val<<endl;
    }
};

If I write my main function as

int main()
{
    vector<A> v1;
    A a2(200);
    v1.push_back(move(a2));              
}

The output is

M Value -> 200
Move Cons...

Which is expected, but if I changed my main function as

int main()
{
    vector<A> v1;
    A a2(200);
    v1.push_back(A(100));
    v1.push_back(move(a2));

}

I get the following output

M Value -> 100
Move Cons...
M Value -> 200
Move Cons...
Copy Cons..   // unexpected
Value -> 0    // unexpected

Can anyone help me in understanding where and how this copy constructor gets called.. that too with value 0

Thanks

Upvotes: 4

Views: 172

Answers (1)

Germ&#225;n
Germ&#225;n

Reputation: 579

The reasons were already answered in the comments. I will try to illustrate what's going on.

Steps:

vector<A> v1;

  1. Allocation of the vector. It internally reserves space for one element.

v1.push_back(A(100));

  1. Construct and the move of A(100) inside the vector.

v1.push_back(move(a2));

  1. Since you are trying to insert a new element, exceeding actual maximum size, vector it's reallocated to a new memory space. Remember that std::vector keeps its content in contiguous memory.
  2. Move a2 inside the v1.
  3. Copy the rest of elements (in this case only the first one) of original v1 to the new v1.

Memory:

1) ## v1[undef ] #########################
2) ## v1[A(100)] #########################
3) ##   [A(100)] ### v1[undef,  undef ] ##
4) ##   [A(100)] ### v1[undef,  A(200)] ##
5) ##   [A(100)] ### v1[A(100), A(200)] ##

Additional notes:

Related to the value 0, that's because these copy and move constructors actually do nothing and val value remain undefined. With proper constructors, this log should be 100.

If you mark the move constructor as noexcept, it will be used in the reallocation process instead of the copy one.

You can use v1.emplace_back(100) instead of v1.push_back(A(100)) avoiding move.

Upvotes: 1

Related Questions