Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11: 'decltype class instance declaration' with std::move( ) doesn't call 'move constructor.' Why?

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

like image 884
Kiseong Yoo Avatar asked Jul 16 '18 15:07

Kiseong Yoo


People also ask

Is move constructor automatically generated?

No move constructor is automatically generated.

What does std :: move do?

std::move. std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.

What is a move constructor?

A move constructor allows the resources owned by an rvalue object to be moved into an lvalue without creating its copy. An rvalue is an expression that does not have any memory address, and an lvalue is an expression with a memory address.


2 Answers

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.

like image 113
François Andrieux Avatar answered Oct 31 '22 14:10

François Andrieux


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.

like image 26
lubgr Avatar answered Oct 31 '22 15:10

lubgr