I want to know if there is a safe programming practice that would alert a coder to this subtle behavior when it takes place or, even better, avoid it in the first place.
A user of struct A
might not realize there is no move constructor. In their attempt to call the absent ctor they get neither a compiler warning or any run-time indication that a copy ctor was called instead.
An answer below explains the conversion that takes place but I don't see any rationale for this being a good thing. If the constructor taking a const reference as a parameter were missing there would be a compile time error rather than just resolving to the non-const reference version. So why wouldn't an attempt at using move semantics result in a compile time error when there is no move semantics implemented in the class?
Is there a way to avoid this behavior with some compile time option or at least a way to detect it during run time?
One could assert(source is null)
after the move if they were anticipating the problem but that is true of so many problems.
Example, when:
struct A {
A() {...}
A(A &a) {...}
A(A const & A) {...}
};
is constructed as in:
A a1;
A a2 = std::move(a1); //calls const copy (but how would I know?)
this results in the const version of the copy ctor being called. Now two objects might have a pointer to a single resource while one of them is likely to be calling it's destructor soon.