Compiler not generating move constructors

  • A+
Category:Languages

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 obverse the same thing 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.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: