In the following code, why is the move constructor not called by the vector implementation if there is a copy constructor? I know it can call the move constructor since it does if there is no copy constructor:
#include <iostream>
#include <vector>
class Cls1 {
public:
Cls1() { std::cout << "default ctor\n"; } // default constructor
Cls1(Cls1&&) { std::cout << "move ctor\n"; } // move constructor
};
class Cls2 {
public:
Cls2() { std::cout << "default ctor\n"; } // default constructor
Cls2(Cls2 const&) { std::cout << "copy ctor\n"; } // copy constructor
Cls2(Cls2&&) { std::cout << "move ctor\n"; } // move constructor
};
template<typename T>
void test(T t1) {
std::vector<T> v;
std::cout << "First push:\n";
v.push_back(std::move(t1));
std::cout << "\nSecond push:\n";
v.push_back(std::move(t1));
std::cout << "\nThird push:\n";
v.push_back(std::move(t1));
std::cout << "\nresize:\n";
v.reserve(100);
std::cout << "\n\n";
}
int main() {
std::cout << "Cls1 - no copy constructor\n";
Cls1 a;
test(std::move(a));
std::cout << "Cls1 - with copy constructor\n";
Cls2 b;
test(std::move(b));
return 0;
}
You can see this here: http://cpp.sh/7wlo
The output I am getting for recent versions of both clang and gcc (using mingw) as well as whatever compiler is at the site linked above show that for Cls2
the vector uses the copy constructor whenever it has to resize it's internal buffer and so misses an opportunity to optimize to a move. This is true for all levels of optimization.
Here is a sample output from running the above code. I noted the "wrong" lines:
Cls1 - no copy constructor
default ctor
move ctor
First push:
move ctor
Second push:
move ctor
move ctor
Third push:
move ctor
move ctor
move ctor
resize:
move ctor
move ctor
move ctor
Cls1 - with copy constructor
default ctor
move ctor
First push:
move ctor
Second push:
move ctor
copy ctor <--
Third push:
move ctor
copy ctor <--
copy ctor <--
resize:
copy ctor <--
copy ctor <--
copy ctor <--
NOTE: VS2015 actually seems to get this right.