5

I recently started using c++ and I chose to learn c++11 features. But how c++ codes run is sometimes not so tangible.

below is my code. At the part with decltype(std::move(sample)) sample2 = std::move(sample); I'm not sure why this line doesn't call move constructor. Could you explain why?

#include <iostream>

class AAA
{
   public:
      AAA() { std::cout << "default constructor" << std::endl; }
      AAA(const AAA& cs) { std::cout << "copy constructor" << std::endl; }
      AAA(AAA&& cs) { std::cout << "move constructor" << std::endl; }
      ~AAA() { std::cout << "destructor" << std::endl; }
};

int main(int argc, char* args[])
{
    AAA sample;
// ((right here))
    decltype(std::move(sample)) sample2 = std::move(sample); 
    return 0;
}

It is compiled on [ ubuntu 16.04 LTS ] with [ gcc 5.4.0 ]

original code : https://ide.geeksforgeeks.org/tALvLuSNbN

antzshrek
  • 9,276
  • 5
  • 26
  • 43
Kiseong Yoo
  • 97
  • 1
  • 7
  • @user202729 pretty sure the `= std::move(sample)` has nothing to do with the `decltype` – Fureeish Jul 16 '18 at 15:17
  • 7
    That line is `AAA&& sample2 = std::move(sample);` which isn't supposed to cause a construction any more than `AAA& sample2 = sample;`. – François Andrieux Jul 16 '18 at 15:19
  • 4
    @FrançoisAndrieux that should be an answer – Fureeish Jul 16 '18 at 15:21
  • @user202729 thanks for your advice – Kiseong Yoo Jul 16 '18 at 15:22
  • @FrançoisAndrieux :) Thx. Your answer seems clear. I'll try to understand that sentence... maybe by googling?? – Kiseong Yoo Jul 16 '18 at 15:27
  • @KiseongYoo Let me know what part is confusing you and I'll try to form an answer. – François Andrieux Jul 16 '18 at 15:28
  • @FrançoisAndrieux I think I'm confused with lvalue/rvalue. => in my code { const int& x7 = -7; } is x7 rvalue? that's why assigning int(rvalue) to x7 succeeded?? similarily decltype(std::move(sample)) == AAA&& so sample2 becomes rvalue? then { auto sample3 = std::move(sample); } works because rvalue can be assigned to lvalue, right? – Kiseong Yoo Jul 16 '18 at 15:37
  • @KiseongYoo If it has a name or it's address can be taken, then it's not an `rvalue`. `x7` clearly has a name so it cannot be an rvalue. `-7` is an integer literal and is a prvalue (a type of rvalue). – François Andrieux Jul 16 '18 at 15:39
  • @FrançoisAndrieux { const int& x7 } is an lvalue. I missed it. – Kiseong Yoo Jul 16 '18 at 15:39
  • 1
    @KiseongYoo You should be aware of an exception in the language which allows temporaries to be bound to `const T &`, which in some cases can extend the lifetime of the temporary. See [this question](https://stackoverflow.com/questions/2784262/does-a-const-reference-prolong-the-life-of-a-temporary). – François Andrieux Jul 16 '18 at 15:41
  • Welcome to SO. It will good for you learn how to create a [mcve] when you run into a problem. Such an example demonstrating your question can be seen at https://ideone.com/vs2rge. – R Sahu Jul 16 '18 at 15:42
  • @FrançoisAndrieux woow, I didn't know that. thanks :) – Kiseong Yoo Jul 16 '18 at 15:49
  • @RSahu should I modify my code? – Kiseong Yoo Jul 16 '18 at 15:49
  • @KiseongYoo, I would say, yes. – R Sahu Jul 16 '18 at 15:50

2 Answers2

6

Your snippet expands to

AAA&& sample2 = std::move(sample);

which binds an rvalue (the result of std::move(sample)) to an rvalue reference (sample2). No new object is constructed, and hence no such constructor is called.

lubgr
  • 37,368
  • 3
  • 66
  • 117
6

The function std::move<T> returns a T &&, so for std::move(sample) it returns AAA &&. This is an rvalue reference and behave a lot like an lvalue reference (a type like AAA & would be an lvalue reference) in that they both are alias to objects that already exist.

It's important to understand that std::move does not in itself cause anything to be moved. It simply returns an rvalue reference to the argument it's given. For example std::move(foo); alone does absolutely nothing. It's only when the result is used to initialize or assign to an object that it becomes useful.

For example auto bar = std::move(foo); will return an rvalue reference to foo and use that reference to call bar's constructor.

To answer the question, since std::move(sample) returns a AAA &&, the line in question is the same as AAA && sample2 = std::move(sample);. The behavior is practically the same as AAA & sample2 = sample;. In both cases, you are initializing a reference to an existing object and no new object needs to be constructed.

If your goal is to move sample into a new AAA, the correct line would be auto sample2 = std::move(sample); like you do with sample3. Though beware that the line sample3 is moving from an already moved-from sample.

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
François Andrieux
  • 28,148
  • 6
  • 56
  • 87