Possible Duplicate:
Move constructor signature
struct X { X(X&); // (1) X(X&&); // (2) X(const X&); // (3) X(const X&&); // (4) }; Are there any situations where (4) will be picked in overload resolution?
Possible Duplicate:
Move constructor signature
struct X { X(X&); // (1) X(X&&); // (2) X(const X&); // (3) X(const X&&); // (4) }; Are there any situations where (4) will be picked in overload resolution?
Yes. One situation is when you have a function with a const return value:
const X f(); X x(f()); f() = x in C++03, but nowadays that habit has to go away because it inhibits move semantics.+ for instance, you don't want to allow x + y = z.foo(x+y) to move, no?Another situation is when you are applying std::move to a const object, as in the following example:
#include <iostream> using namespace std; struct X { X() { cout << "default" << endl; } X(X&) { cout << "non const copy" << endl; } // (1) X(X&&) { cout << "non const move" << endl; } // (2) X(const X&) { cout << "const copy" << endl; } // (3) X(const X&&){ cout << "const move" << endl; } // (4) }; void f(X const x) { } int main() { X const x; f(std::move(x)); return 0; } The case mentioned in a previous answer (X const f()) is probably less common, because the move constructor is most of the times elided by the compiler when doing RVO (this can be done even if the constructor has side-effects).
Moving a const object into another const object as a logical operation does make sense, and if you do not define a const move constructor then you won't be allowed to do that. Moving is just transferring ownership, so it seems to me that as a logical operation it should be supported.
Although it is true that from a high-level viewpoint you are not supposed to modify a const object and indeed moving an object requires modifying it (in most cases), there are well-known similar situations where it is OK to modify a const object "behind the scenes" for the purpose of realizing a higher-level conceptual operation. Think for instance of a const member function that needs to lock a non-const member mutex: you may declare the mutex variable as mutable to treat it as a non-const object.
So even in this case I see it as a legitimate operation in a const move constructor (as long as it is needed) to modify mutable members of the moved object (perhaps some boolean flag to be checked by the object's destructor). Please notice, that if you remove the const constructors (3) and (4) from the code above, then it won't compile. If you remove only (4), the copy constructor (3) will be chosen - meaning you won't be able to move the const object.
const_cast away the constness and then do a normal move. I don't think this is const correct at all. A const move constructor should do exactly the same as the copy constructor. It makes no sense to move a const object.const is Undefined Behavior. So a safe const move constructor would not change the source in any circumstances. But then it's the same as the copy constructor, and there's no point in declaring the overload.const object may have mutable members that can be modified by a const move constructor. As I mentioned in a previous comment, the pattern is the same as when you want to lock a member mutex inside a const function.struct X { [...] X(const X&& other){ other.flag = false; cout << "const move" << endl; } mutable bool flag = true; }; This code is legal.mutable values of a const objects. That makes it possible to move from a constant source. For instance I can imagine a vector class (not std::vector of course) whose const move constructor simply copies the data pointer and the size counter (and other stuff if necessary), and sets a mutable flag in the moved object to false, so that the destructor of that object won't try to deallocate the memory. No element-wise copy will occur, no double deallocation, so that's an effective, safe, and legal move of such a const vector. Am I wrong?