2

I was trying to test the behavior of compiler generated Move Constructor for a class having data members as "std::string" and "std::shared_ptr".

class Record
{
public:

Record():mData("defRec"), mDataPtr(new std::string("defRec"))
{}

Record(const std::string &str): mData(str), mDataPtr(new std::string(str))
{}

private:

std::string mData; 
std::shared_ptr<std::string> mDataPtr;
};

Any D'tor, move and copy operations have been deliberately omitted to allow compiler to generate Move operations. The class data members have especially been chosen since unlike the Record class, they both have D'tor, move and copy operations defined.

After the following code,

Record rec1(std::string("Record1"));
Record rec2(std::move(rec1));

on inspecting object rec1 (via debugger or by defining access methods), mData still contains "Record1" and mDataPtr still holds the string pointer.

However, If I provide my own Move Constructor as below

Record(Record&& rhs) : mData(std::move(rhs.mData)), mDataPtr(std::move(rhs.mDataPtr))
{}

then after the following code

Record rec1(std::string("Record1"));
Record rec2(std::move(rec1));

on inspecting object rec1, both mData and mDataPtr become empty object.

I don't understand why the compiler generated move constructor for "class Record" gives different result to my version of move constructor for "class Record" where I just ensure the move C'tor for data members to be invoked. I would expect the same behavior for compiler generated move constructor?

Though the moved from object is supposed to be in a valid state, the data members' move constructor (not defined by me on both occasions) gives different results.

Is this a known limitation of VC12 (VS2013)?

Rahul
  • 21
  • 1

1 Answers1

4

Yes this is a known limitation of that compiler. From Can a move constructor be implicit? the question's EDIT EDIT shows us:

EDIT EDIT I pinged Stephan T Lavavej and asked him why VC 2012 doesn't seem to follow what draft 12.8 states regarding implicit move constructor generation. He was kind enough to explain:

It's more of a "feature not yet implemented" than a bug. VC currently implements what I refer to as rvalue references v2.0, where move ctors/assigns are never implicitly generated and never affect the implicit generation of copy ctors/assigns. C++11 specifies rvalue references v3.0, which are the rules you're looking at.

In short the move constructor is never being generated by the compiler and the copy constructor is called instead even in the presence of the explicit std::move.

According to the standard, there are a bunch of reasons the compiler wouldn't be required to generate a default move constructor but your class doesn't appear to violate any of them.

Community
  • 1
  • 1
Mark B
  • 95,107
  • 10
  • 109
  • 188