C ++ 11:带有std :: move()的'decltype类实例声明'不调用'move构造函数'。为什么?

时间:2018-07-16 15:15:11

标签: c++ c++11 move-semantics decltype stdmove

我最近开始使用 c ++ ,我选择学习 c ++ 11 功能。 但是,c ++代码的运行方式有时并不那么切实。

下面是我的代码。 在decltype(std::move(sample)) sample2 = std::move(sample);部分,我不确定为什么此行不调用move构造函数。 你能解释为什么吗?

#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;
}

使用[gcc 5.4.0]在[ubuntu 16.04 LTS]上编译

原始代码:https://ide.geeksforgeeks.org/tALvLuSNbN

2 个答案:

答案 0 :(得分:6)

您的代码段扩展为

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

它将右值(std::move(sample)的结果)绑定到右值引用(sample2)。没有构造新对象,因此没有调用此类构造函数。

答案 1 :(得分:6)

函数std::move<T>返回一个T &&,因此对于std::move(sample),它返回AAA &&。这是一个rvalue reference,其行为非常类似于lvalue reference(像AAA &这样的类型将是左值引用),因为它们都是已存在对象的别名。

重要的是要了解std::move本身不会 引起任何移动。它只是返回对给定参数的右值引用。例如,仅std::move(foo);绝对没有任何作用。只有当结果用于初始化或分配给对象时,它才变得有用。

例如auto bar = std::move(foo);将返回对foo的右值引用,并使用该引用来调用bar的构造函数。

要回答这个问题,由于std::move(sample)返回了AAA &&,因此所讨论的行与AAA && sample2 = std::move(sample);相同。该行为实际上与AAA & sample2 = sample;相同。在这两种情况下,您都将初始化对现有对象的引用,并且不需要构造任何新对象。

如果您的目标是将sample移至新的AAA,则正确的行应该是auto sample2 = std::move(sample);,就像您对sample3所做的那样。尽管请注意,行sample3正在从已经移出的sample中移出。