I have the following situation: A tuple containing a custom class is stored in a vector.
struct A {
string m_name;
void cp(const A& x) { m_name = x.m_name; cout << m_name << ": copy "; }
void mv(A&& x) { m_name = move(x.m_name); cout << m_name << ": move "; }
A(const string& n) : m_name(n) { cout << "ctor" << endl; }
A(A&& x) { mv(move(x)); cout << "ctor" << endl; }
A(const A& x) { cp(x); cout << "ctor" << endl; }
A& operator=(A&& x) { mv(move(x)); cout << "ass-op" << endl; return *this; }
A& operator=(const A& x) { cp(x); cout << "ass-op" << endl; return *this; }
~A() noexcept { cout << m_name << ": dtor " << endl; }
};
using t_tuple = tuple<string, A>;
vector<t_tuple> v;
void store_in_vector(const string& s, A&& a) {
v.emplace_back(s, move(a));
}
On insert elements in the vector, I recognized that the copy constructor of A
is being called whenever the std::vector
has to resize itself internally.
Here is my test code:
store_in_vector("a", A("a"));
store_in_vector("b", A("b"));
store_in_vector("c", A("c"));
store_in_vector("d", A("d"));
store_in_vector("e", A("e"));
store_in_vector("f", A("f"));
store_in_vector("g", A("g"));
store_in_vector("h", A("h"));
store_in_vector("i", A("i"));
store_in_vector("j", A("j"));
store_in_vector("k", A("k"));
store_in_vector("l", A("l"));
The output looks like follows after inserting the "b" element
ctor
b: move ctor
a: copy ctor
a: dtor
: dtor
Why is the copy constructor being called? Wouldn't it be more optimal if std::vector
called the MOVE constructor? What I am confused about is the following: If I change struct A
to the following implementation which deletes the copy constructor, it actually calls the MOVE constructor when the vector is resized.
Here is the modified implementation of struct A
:
struct A {
string m_name;
void cp(const A& x) { m_name = x.m_name; cout << m_name << ": copy "; }
void mv(A&& x) { m_name = move(x.m_name); cout << m_name << ": move "; }
A(const string& n) : m_name(n) { cout << "ctor" << endl; }
A(A&& x) { mv(move(x)); cout << "ctor" << endl; }
A(const A& x) = delete;
A& operator=(A&& x) { mv(move(x)); cout << "ass-op" << endl; return *this; }
A& operator=(const A& x) = delete;
~A() noexcept { cout << m_name << ": dtor " << endl; }
};
which shows this output after inserting element "b":
ctor
b: move ctor
a: move ctor
: dtor
: dtor
Everything seems to work normally, and in my optnion, the code calling the move constructor should be more optimal (i.e. faster, less overhead). However, I don't understand why this happens. How could I change the implementation of struct A
to get the move constructor called without deleting the copy constructor? If there is any good reason why the copy constructor gets called in the frist version, please explain!
I am using Xcode with Apple LLVM 6.1