I am trying to understand the move semantics are looking in to compiler generated move constructors (copy and assignment).
In Modern Effective C++, Scott Meyers says in Item #17 that if no explicit copy constructors are declared, the the compiler will generate move constructors, which will do member-wise move for non-static
members.
To confirm this, I am trying below code:
#include <iostream>
#include <string>
using namespace std;
class A
{
private:
std::string str;
public:
A() : str("Init string")
{
cout << "Default constructor" << endl;
}
A(std::string _str) : str(_str)
{
cout << "Constructor with string" << endl;
}
std::string getString()
{
return str;
}
};
int main() {
A obj1;
A obj2("Obj2 string");
cout << endl;
cout << "obj1: " << obj1.getString() << endl;
cout << "obj2: " << obj2.getString() << endl;
obj1 = std::move(obj2);
cout << endl;
cout << "obj1: " << obj1.getString() << endl;
cout << "obj2: " << obj2.getString() << endl;
return 0;
}
The output is:
Default constructor
Constructor with string
obj1: Init string
obj2: Obj2 string
obj1: Obj2 string
obj2: Obj2 string
But I expected it to be:
Default constructor
Constructor with string
obj1: Init string
obj2: Obj2 string
obj1: Obj2 string
obj2:
Because obj2.str would have been moved and now has an empty string.
What is the reason the compiler is not generating a move assignment constructor and invoking the copy assignment operator?
EDIT: Implementing the move assignment operator as below gives the expected output (i.e. empty string after calling std::move)
A& operator=(A&& obj)
{
cout << "Move assignment operator" << endl;
str = std::move(obj.str);
return *this;
}
Firstly, obj1 = std::move(obj2);
invokes assignment operator, so it has nothing to do with constructors.
Yes, The compiler generates a move assignment operator for A
, which perform member-wise move operation, including data member str
. The problem is that after move operation str
is left in valid, but unspecified state. Also see std::basic_string::operator=
.
Replaces the contents with those of
str
using move semantics.str
is in a valid but unspecified state afterwards.
I think you might observe the same result with only std::string
, e.g.
std::string str1 = "Init string";
std::string str2 = "Obj2 string";
str1 = std::move(str2);
std::cout << str2;
LIVE with clang, just for reference; it gives the result as you expected but still remember the result is unspecified.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With