Why is copy constructor called twice?

Viewed 88

I have the following code snippet

#include <iostream>
#include <vector> 

class Move {
    private:
        int* data;
         
    public: 
        void set_data_value(int d) {
            *data = d; 
        }
        int get_data_value(){
            return *data; 
        }

        Move(int d);
        Move(const Move &source);
        ~Move();
};

Move::Move(int d) {
    std::cout << "ctor being called" << std::endl; 
    data = new int; 
    *data = d; 
}

Move::Move(const Move& source) {
    std::cout << "copy ctor being called" << std::endl;
    data = new int; 
    *data = *source.data;
}

Move::~Move() {
    std::cout << "deleting Move" << std::endl; 
    delete data; 
}
int main() {
    Move x{1};
    
    Move y{x}; 

    std::vector<Move> vec; 
    vec.push_back(x);
    vec.push_back(y);

    return 1; 

}

Here is the output:

ctor being called
copy ctor being called
copy ctor being called
copy ctor being called
copy ctor being called
deleting Move
deleting Move
deleting Move
deleting Move
deleting Move

My question is: why is the copy constructor being called 4 times when I see only 3 copies? (1 from Move y{x} and two from the two push_back() calls)

2 Answers

You miss to count reallocations of the vector. Add this lines to your code:

int main() {
    Move x{1};
    
    Move y{x}; 

    std::vector<Move> vec; 
    std::cout << "capacity: " << vec.capacity() << "\n";
    vec.push_back(x);
    std::cout << "capacity: " << vec.capacity() << "\n";
    vec.push_back(y);
    std::cout << "capacity: " << vec.capacity() << "\n";

    return 1; 

}

Then possible output is:

ctor being called
copy ctor being called
capacity: 0
copy ctor being called
capacity: 1
copy ctor being called
copy ctor being called
deleting Move
capacity: 2
deleting Move
deleting Move
deleting Move
deleting Move

The vectors capacity starts out as 0 and then increases as needed (factors of 2 or 3 are common). You can see that when the capacity increases from 1 to 2, there is a call to the copy constructor to copy that one element that is already in the vector to a different place in memory.

Note that the output of the above can be different. Allocation strategies are subject to subtle optimizations. Its the requirement of push_back having amortized constant complexitiy that implies that capacity cannot grow linear. Though the factor is not necessarily 2. Some implementations use 3 or a different factor.

Related