6

[C++11: 12.8/3]: A non-template constructor for class X is a move constructor if its first parameter is of typeX&&, const X&&, volatile X&&, or const volatile X&&, and either there are no other parameters or else all other parameters have default arguments (8.3.6). [..]

Why is a constructor that takes a const rvalue reference called a "move constructor" by the standard? Surely it's self-evident that this prohibits meaningful move semantics in all but the most fringey cases?

"According to me", as the SO saying goes, T(const T&&) shouldn't be deemed a "move constructor" as such, since it's basically useless.

If anything, shouldn't it be called a copy constructor?

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • The same as copy constructors taking non-const lvalue refs. – Puppy Jun 30 '14 at 10:29
  • 4
    The "move constructor" could rip out `mutable` guts, could it not? ;) – fredoverflow Jun 30 '14 at 10:35
  • @FredOverflow: So could a copy constructor – Lightness Races in Orbit Jun 30 '14 at 10:35
  • 2
    My guess is that if you have a constructor that takes `const X&&`, then your class probably has some unusual semantics and it would not make sense for a "real" move constructor to be implicitly defined. So we just say that the `const X&&` constructor is a move constructor. What you call it doesn't matter otherwise (I think). – Brian Bi Jun 30 '14 at 10:36
  • @Brian: Then it shouldn't be a move _or_ copy constructor! – Lightness Races in Orbit Jun 30 '14 at 10:55
  • 1
    @LightnessRacesinOrbit: Wait, so you think it's *reasonable* for a **copy** constructor to *move* out the `mutable` guts of another `const` object? – user541686 Jun 30 '14 at 10:57
  • @Mehrdad: No, I don't. – Lightness Races in Orbit Jun 30 '14 at 10:58
  • 1
    So how is a copy constructor being able to do that a response to @FredOverflow's comment? – user541686 Jun 30 '14 at 10:58
  • @Mehrdad: He seemed to be suggesting that because this "move constructor" could rip out `mutable` guts, that is enough reason for it to be a move constructor. But, since copy constructors can do that too, and they are obviously not move constructors, it's a vacuous argument. That was my point. – Lightness Races in Orbit Jun 30 '14 at 11:04
  • @LightnessRacesinOrbit: If you replace the word "rip" with the word "move" I think you will see why it's in fact a perfectly logical and reasonable argument. – user541686 Jun 30 '14 at 11:06
  • @Mehrdad: If you actually read my comment I think you will see why it's not. Otherwise you are suggesting that copy constructors can just as sanely be known as "move constructors". – Lightness Races in Orbit Jun 30 '14 at 11:07
  • @LightnessRacesinOrbit: Yeah, move constructors can copy too, why shouldn't we call them copy constructors?! – user541686 Jun 30 '14 at 11:19
  • @Mehrdad: Move constructors can also do absolutely nothing at all if they like; slippery-slope argument defeated – Lightness Races in Orbit Jun 30 '14 at 11:27
  • 1
    Isn't this just principle of least surprise? Whether the construct is actually useful or not doesn't seem that interesting. – Tim Seguine Jun 30 '14 at 11:53
  • I think it is unlikely there would be a use case for this. You would need a perfect storm: a need for returning `const` temporaries **and** a need to distinguish them semantically from non-`const` temporaries. Both seem pretty one in a million to me. – Tim Seguine Jun 30 '14 at 12:17
  • @TimSeguine: Yes, I think it _is_ PoLS, and I think it's incredibly surprising that a constructor typically incapable of moving shall be called a move constructor and enjoy all the benefits of one. Whether the construct is actually useful should have been considered in committee because it seems pretty blooming relevant to me! – Lightness Races in Orbit Jun 30 '14 at 12:17
  • @LightnessRacesinOrbit I take the opposite opinion. I would have suspected before reading the passage, that they are called move constructors (given that the word seems to be deeply ingrained in the `&&` syntax) It would seem like an arbitrary/pointless exception to have excluded it. – Tim Seguine Jun 30 '14 at 12:18
  • @TimSeguine: It would not have been an exception to exclude it; it has been explicitly included. Listed out. With additional characters in the standard text to make that so! I'm asking why. – Lightness Races in Orbit Jun 30 '14 at 12:19
  • I know it has been explicitly included. I am saying many people associate `&&` as being synonymous with 'move'. It is those people that aren't being surprised. Anyone who thinks about it long enough to come to your conclusion that they are useless and can't possibly be used to actually move something are never going to use the syntax anyway (IMO). – Tim Seguine Jun 30 '14 at 12:22

1 Answers1

9

Here are some of the differences between move constructors and other constructors:

  • Move constructors can be defaulted
  • Move constructors don't prevent a type from being a "literal type"
  • Non-trivial move constructors prevent a type from being a "trivially copyable type"
  • Move constructors prevent the implicit move constructor from being generated
  • Move constructors may be automatically called by standard library functions

As far as I can tell, for all of those, not calling X(const X &&) a move constructor gives undesirable results.

You give an alternative: it might be called a copy constructor instead. That too seems to have undesirable results: it would suppress the implicit copy constructor.

Whether a move constructor actually moves doesn't matter. A POD type may have a move constructor too. It'll just be making a copy, but it's still called a move constructor.

  • Can you expand on what those "undesirable results" would be? If a move constructor doesn't move then what's so special about it? Make it a normal, bog-standard, user-defined constructor. – Lightness Races in Orbit Jun 30 '14 at 10:56
  • @LightnessRacesinOrbit Well, those are the points I listed in my answer: if you don't call it a move constructor, it can't be defaulted, it prevents the type from being a literal type, it *doesn't* prevent the type from being considered trivially copyable (even though the constructor may still be called implicitly), the default move constructor would still be generated, and standard library functions would have to ensure they don't accidentally call any `X(const X &&)` constructor where the standard only allows move constructors to be called. All of those seem undesirable to me. –  Jun 30 '14 at 11:11
  • 1
    Yes, you said that already! I'm asking _why_ those are undesirable. What about `X(const X&&)` failing to prevent a `X(X&&)` from being generated is particularly undesirable? – Lightness Races in Orbit Jun 30 '14 at 11:26
  • 1
    @LightnessRacesinOrbit That's not what you asked, but I should've guessed that that's what you meant, sorry. If you, as the programmer, define a `X(const X &&)` constructor but not a `X(X &&)` constructor, it's far more likely that you don't want a `X(X &&)` constructor, than that you do. And the compiler generally shouldn't silently do something the programmer probably won't want. –  Jun 30 '14 at 11:51
  • Perhaps it comes down to a matter of opinion then because I find it more likely I'd still want a meaningful move constructor, and to do something entirely different with the nonsense `X(const X&&)` :P – Lightness Races in Orbit Jun 30 '14 at 11:53
  • 1
    @LightnessRacesinOrbit For the other points: the advantages of being able to define `X(const X &&) = default;` are the same as those of being able to define `X(X &&) = default;`. Labelling a type with a non-trivial `X(const X &&)` constructor as trivially copyable (inspectable via type traits) may break standard library functions optimised for trivially copyable types. –  Jun 30 '14 at 11:54
  • @LightnessRacesinOrbit Sure, I'd probably never use a `X(const X &&)` constructor either, regardless of what it's called. :) It's just that *if* it's defined anyway, I can see why it would still be called a move constructor. –  Jun 30 '14 at 11:55
  • 1
    Well at least it's consistent with the barmy naming of `std::move`. The standard seems to use "copy" to mean "things to do with lvalue values/refs" and "move" to mean "things to do with rvalue refs", which is silly. – Lightness Races in Orbit Jun 30 '14 at 12:18
  • @Lightness I think that is just an accident of circumstance. And C++ generally keeps its accidents once they are standardized. – Tim Seguine Jun 30 '14 at 12:29
  • 1
    @LightnessRacesinOrbit Right, you can read "copy constructor" as "lvalue copy constructor", and "move constructor" as "rvalue copy constructor" if you prefer, and the standard might have been somewhat clearer if that's what it called such constructors. Then again, a `X(const X &)` constructor might be called with an rvalue too. I don't think there is a perfect name that accurately captures both the intended semantics and the implementation details, yet is sufficiently succinct that the standard can use that name throughout. –  Jun 30 '14 at 12:36