7

From this reference, it allows a const rvalue as a move constructor

Type::Type( const Type&& other );

How can a movable object be const? Even if this was technically allowed, is there a case where such declaration would be useful?

David G
  • 94,763
  • 41
  • 167
  • 253
balki
  • 26,394
  • 30
  • 105
  • 151
  • 4
    Simple answer: No, there is not, as it defeats the whole purpose of move-semantics. Also note that `&&` doesn't necessarily say "movable". It just says "rvalue reference". And *MoveConstructible* falls back on copying if there is no move ctor, so you could say the `T const&&` move ctor might just copy, but eh. – Xeo Dec 28 '12 at 10:25
  • Well, `Type` may declare a `mutable` variable and `mutable` variables *can* be modified by `const` move constructors. So a `const` move constructor could just do a shallow copy of the object (while a copy constructor might do a deep copy) and set a `mutable` boolean flag called `dead` or something like that to `true` on the moved object. Then functions of `Type` (most importantly the destructor) would check that flag. Is this nonsense? – Andy Prowl Dec 31 '12 at 16:04

2 Answers2

8

How can a movable object be const?

It can't, but that's not what the language says. The language says that a constructor with that signature is a "move constructor" but that doesn't mean the argument gets moved from, it just means the constructor meets the requirements of a "move constructor". A move constructor is not required to move anything, and if the argument is const it can't.

is there a case where such declaration would be useful?

Yes, but not very often. It can be useful if you want to prevent another constructor being selected by overload resolution when a const temporary is passed as the argument.

struct Type
{
  template<typename T>
    Type(T&&);  // accepts anything

  Type(const Type&) = default;    
  Type(Type&&) = default;
};

typedef const Type CType;

CType func();

Type t( func() );   // calls Type(T&&)

In this code the temporary returned from func() will not match the copy or move constructors' parameters exactly, so will call the template constructor that accepts any type. To prevent this you could provide a different overload taking a const rvalue, and either delegate to the copy constructor:

Type(const Type&& t) : Type(t) { }

Or if you want to prevent the code compiling, define it as deleted:

Type(const Type&& t) = delete;

See https://stackoverflow.com/a/4940642/981959 for examples from the standard that use a const rvalue reference.

Community
  • 1
  • 1
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
0

Some background on this feature's intent.

Rvalue references - From Bjarne Stroustrup's Blog

A Proposal to Add Move Semantics Support to the C++ Language

An interesting question. I read, somewhere, an explanation of this question by Stroustrup, but can't seem to find it back. Hope the above helps in its stead.