For the following example, why the vector move operation is not triggered? How do I know when I should explicitly use a move operator?
#include <iostream>
#include <vector>
using namespace std;
class Test {
public:
Test() {
std::cout << " default " << std::endl;
}
Test(const Test& o) {
std::cout << " copy ctor " << std::endl;
}
Test& operator=(const Test& o) {
std::cout << " copy assign " << std::endl;
return *this;
}
Test(Test&& o) {
std::cout << " move ctor" << std::endl;
}
Test& operator=(Test&& o) {
std::cout << " move assign " << std::endl;
return *this;
}
};
int main()
{
std::cout << " vector: " << std::endl;
std::vector<Test> p;
p = {Test()}; // expect vector move here since the RHS is temporary.
std::cout << std::endl;
std::cout << " single value " << std::endl;
Test tt;
tt = Test();
}
Output:
vector:
default
copy ctor
single value
default
default
move assign
I was under the impression that when we assign a temporary variable to a lvalue (the single value case in the example), it would trigger a move operation if it exists. Seems that I was wrong and my understanding was overly simplified, I need to carefully check case by case to ensure there's no redundant copy.
CodePudding user response:
std::vector
has an assignment operator that takes an std::initializer_list
:
vector& operator= (initializer_list<value_type> il);
So when you wrote p = {Test()};
you're actually using the above assignment operator.
Now why a call to the copy constructor is made can be understood from dcl.init.list, which states:
An object of type
std::initializer_list<E>
is constructed from an initializer list as if the implementation allocated a temporary array ofN
elements of typeconst E
, whereN
is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std::initializer_list object is constructed to refer to that array.