1

I was playing with this example in order to understand rvalue references:

#include <string>
#include <iostream>
#include <utility>
#include <vector>

class Dog
{
public:
    Dog() {};
    Dog(Dog&& a) {  std::cout << "R value" << std::endl;}
};

Dog foo()
{
    return Dog();
}

int main()
{
    std::vector<Dog> v;
    v.push_back(Dog()); // calls move constructor

    Dog c((Dog())); // does not call move constructor
    Dog d(foo()); // does not call move constructor
}

I struggle to understand why in the line v.push_back(Dog()), object Dog() is treated as an Rvalue (so the move constructor is called), but the following two lines do not call move constructors. I guess I might be misunderstanding the relationship between an anonymous object and RValue here.

H Xu
  • 305
  • 1
  • 8
  • 1
    Look up RVO and NRVO and put messages in your constructor and add a destructor with a message (hint `c` and `d` are probably being constructed in-place). If you are testing this sort of thing it is useful to implement (and instrument) all the constructors (normal, copy, move) and also the destructor. – Richard Critten May 17 '17 at 13:03
  • Yes it's completely up to RVO and NRVO. Thanks – H Xu May 17 '17 at 13:43

1 Answers1

5

This is because of Return Value Optimization. Your compiler is smart enough to see that the last 2 lines can be simplified to:

Dog c;
Dog d;

So it is allowed to just rewrite your code to above code. Since push_back does not meet the requirements under which RVO are allowed a temporary is created and simply moved as you witnessed. Try adding prints to the constructor and it'll get clearer.

Community
  • 1
  • 1
Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
  • 1
    Ah, equally struggling to understand how Bill Gates from Microsoft comes to answer my question :) Thanks – H Xu May 17 '17 at 14:03