为什么在我的代码中调用复制构造函数而不是移动构造函数?

问题描述 投票:2回答:2

我正在尝试了解move构造函数和右值引用。因此,我在https://www.onlinegdb.com/online_c++_compiler上尝试了此代码。但是结果使我感到困惑。

#include <iostream>
#include <type_traits>


class A {
public:
  A() { std::cout << "Constructed" << std::endl; }
  A(const A& )= delete;
  A(A&&) { std::cout << "Move Constructed" << std::endl; }
};

int
main ()
{
  A&& a = A();
  A b = a; // error: use of deleted function ‘A::A(const A&)’
  //A b = static_cast<decltype(a)>(a); // This works, WTF?
  std::cout << std::is_rvalue_reference<decltype(a)>::value << std::endl; // pretty sure a is rvalue reference.

  return 0;
}
c++ c++11 rvalue-reference
2个回答
3
投票

您对typesvalue categories感到困惑。

(重点是我的)

每个C ++表达式(具有其操作数,文字,变量名等的运算符)的特征是两个独立的属性:类型值类别

作为命名变量,a是一个左值。

以下表达式是左值表达式

  • 变量名,...
  • ...

然后选择A b = a;的复制构造函数。如您所试,static_cast<decltype(a)>(a);会将其转换为xvalue(即rvalue);您也可以使用std::move

A b = std::move(a);

以下表达式是x值表达式

  • 函数调用或重载的运算符表达式,其返回类型是对对象的右值引用,例如std::move(x)
  • ...

0
投票
A&& a = A();

不会给您一个右值。将任何值视为rvalue的一种方法是您无法获取它的地址。如果可以获取它的地址,则可能是左值。所以,在您的情况下

auto address_of_a = &a;

是可能的(因此,a为左值)。

decltype(a)

是A &&(右值类型)。因此,将类型强制转换为A &&会给您右值

A b = a;

失败,因为a是左值,所以它正在寻找A(const A&)。

A b = std::move(a); // or
A b = A{}; // rvalue

将成功,因为它将寻找A(A &&)

A b;
A c = A{};
b = std::move(c);

如果您将移动分配定义为在删除期间失败,则会失败

b = c;

如果您定义副本分配,将会成功。

默认构造/复制构造/移动或复制分配将起作用,只要所有元素都可以被简单地复制/移动。

© www.soinside.com 2019 - 2024. All rights reserved.