Why is the copy constructor called instead of the move constructor?

see the following code example:

#include <iostream> struct Foo { Foo() { std::cout << "Default!\n"; } Foo(const Foo& foo) { std::cout << "Copy!\n"; } Foo(Foo&& foo) { std::cout << "Move!\n"; } }; struct Bar { Foo foo; Bar() {} Bar(Bar &that) : foo(that.foo) {} Bar(Bar &&that) : foo(std::move(that.foo)) {} }; Bar f() { Bar bar; return bar; } int main() { Bar bar(f()); } 

I expect the output of this code should be:

 Default! Move! 

but I get:

 Default! Copy! 

I see no reason why the copy constructor is called instead of the move constructor. If I put the const keyword before Bar &that in the declaration of the copy constructor struct Bar , I have the correct result. I know that in many cases it is better to take a reference to the lvalue constant, and not just the lvalue reference for copy constructors, but I just want to know the reason why this happened.

Why was Bar & preferable to Bar && in this example, although the return value of f() should be considered as prvalue? Why does the const keyword solve the problem? Does const really solve the problem? Is this related to RVO (Return Value Optimization)? Or is it just a compiler error?

I tested this example on Visual C ++ November 2012 CTP.

I found a similar problem:

Instead of the move constructor, the constructor instance is called

But I still can’t understand why.

Can anybody help me?

+5
source share
3 answers

Wow, when I compile this with ...

  • Visual Studio in debugging. I see "Default! Copy!".
  • Visual Studio in the release I see "By default!".
  • If you change Bar(Bar &that) to Bar(const Bar &that) , then "Default! Move!"
  • It's amazing if you switch the order of Bar(Bar &that) to Bar(Bar &&that) (so that the ctor movement is detected first), you will see "Default! Move!"
+3
source

This is just normal Visual C ++ non-compliance, allowing you to bind a non-constant lvalue reference to a temporary one. He violates the language rules, but he is too slow before being caught, so now there is a code that depends on the error that would break if it were fixed.

This behavior, erroneously allowing the use of a non- const copy constructor, combined with incomplete rvalue link support in this version of Visual C ++, seems to lead to the selection of the wrong overload.

If you want to use the features of C ++ 11 / C ++ 14, you are best off staying on top of the latest version of Visual C ++.

+4
source

Your question will probably be answered here .

A temporary object cannot communicate with a non-constant reference. The copy constructor must reference the const object in order to be able to make copies of temporary objects.

Another thing is that temporary objects are not subject to modification, since they should be destroyed in the near future. Saving a link to temporary sections leads to potential modification of non-existent objects due to negligence.

-2
source

All Articles