3

In code like this:

class X {
  X(const X&) {
    // ...
  }

  X(const X&&) {
    // ...
  }

  // ...
};

void f() {
  X a;
  // ...
  X b = a;
  // ... code that doesn't use a
}

My understanding is that the last statement calls the copy constructor not the move constructor. Assuming a is never used again in f(), can the compiler automatically optimize this statement to use the move constructor instead?

P.S. I know about std::move(), but I'm asking about automatic move.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
Haitham Gad
  • 1,529
  • 2
  • 13
  • 23
  • [Related](http://thbecker.net/articles/rvalue_references/section_10.html). [Also related](http://stackoverflow.com/questions/9779079/why-does-c11-have-implicit-moves-for-value-parameters-but-not-for-rvalue-para). Neither really addresses your specific case, though. –  Jun 09 '15 at 20:09
  • 1
    NicolBolas' answer in the second link hvd posted above is applicable to your question too. Automatic move only happens in circumstances where there is no doubt the lifetime of the object is ending (`return` statement). In your case, you'd have to rely on the compiler's static analysis capabilities to move automatically, and the standards committee opted not to go that route. So you must explicitly ask for `a` to be moved. – Praetorian Jun 09 '15 at 20:22

3 Answers3

4

You'd need to write a spec that somehow correctly handles

void f() {
  X a;
  g(a); // stash a reference to a somewhere 
  X b = a; // can't move from a!
  g2(); // use the reference stored by g
}

For the move to be safe, you'd need to prove that subsequent code, including all the functions it calls, does not access a directly or indirectly, which is impossible in the general case because the definitions of these functions may not be available to the compiler (e.g., in a different translation unit).

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • 1
    Note that this also causes problems when implicit move *is* allowed by the Standard (`return` statement) – Ben Voigt Jun 09 '15 at 20:23
  • @BenVoigt Well, in that case the reference/pointer stashed away would have become dangling anyway...? – T.C. Jun 09 '15 at 20:46
  • Not necessarily: locals get destroyed in the opposite order of declaration. Implicit move yanks the object being returned out of that natural order. – Ben Voigt Jun 09 '15 at 21:48
  • @BenVoigt Nope. Implicit move yanks the _contents_ of the object into some other lifespan. The local object that was moved from is still destroyed at the preordained time that the holy scriptures (Standard) dictates. Moving from an object must leave the object in a destroyable state. – Andre Kostur Jun 09 '15 at 21:54
  • @AndreKostur: Right, the contents are lost out of order, and then the object's actual destruction is performed in order. The foundation of T.C.'s answer is that loss of contents is what matters. – Ben Voigt Jun 09 '15 at 21:56
  • @BenVoigt No, the foundation of the answer is that you can't safely implicitly move from `a` because you have a way (because `g()` may have stashed a separate reference to `a`) to go back and look at `a` and can notice that its guts have been stolen. Your original comment is not correct as if you cause `g()` to store a reference to a local variable and that variable goes out of scope, you're already in Undefined Behaviour land, regardless of whether `a` was moved from. That extra reference to `a` is now dangling. – Andre Kostur Jun 09 '15 at 22:11
  • @AndreKostur: I am talking about a scenario that assuredly is NOT undefined behavior in C++03, namely when `g(a) // stash a reference` is construction of another local variable and `g2() // use the reference` is its destructor. This may break in C++11. – Ben Voigt Jun 09 '15 at 22:14
0

It is difficult/impossible for a compiler to know that a is unreferenced except in trivial scenarios. Any outside function could have saved a pointer or reference to a, and any outside function could be relying on said pointer's contents.

In the situation where no outside functions are involved, I guess that optimization could be possible.

StilesCrisis
  • 15,972
  • 4
  • 39
  • 62
0

The optimization would not be entirely safe without more rigorous analysis. For example, a local object might have been initialized with the address of a and do something on it upon destruction, which would happen after the last statement X b = a;.

musiphil
  • 3,837
  • 2
  • 20
  • 26
  • 1
    Note that this also causes problems when implicit move *is* allowed by the Standard (`return` statement) – Ben Voigt Jun 09 '15 at 20:23