std :: move如何复制不可复制的对象?

new*_*bie 3 c++ move-semantics c++11

请考虑以下代码.

#include <iostream>
#include <type_traits>

struct A
{
    int x;
    A() = default;
    ~A() = default;

    A(const A&) = delete;
    A &operator=(const A&) = delete;

    A(A &&) = default;
    A &operator=(A &&a) = default;
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_copy_constructible<A>::value << std::endl;
    std::cout << std::is_copy_assignable<A>::value << std::endl;

    A a;
    a.x = 3;

    A b = std::move(a);

    std::cout << std::hex << a << " " << &b << std::endl;
    std::cout << a.x << " " << b.x;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

示例输入是:

false
false
0xbfd1ee28 0xbfd1ee2c
3 3
Run Code Online (Sandbox Code Playgroud)

如您所见,b虽然该类A在设计上是不可复制的,但已成功复制该变量.我完全理解变量a不会被移动到任何地方.的std::move通话大概应该构建一个右值引用复制对象a第一,但嘿,是不是在类定义禁止?

谁能解释一下,这里发生了什么?

Die*_*ühl 7

为什么你认为有副本?您要求编译器为您生成移动构造函数.生成的移动构造函数将对所有元素进行成员移动.基本上有两种情况:

  1. 相应的成员有一个移动构造函数,在这种情况下,将应用此移动构造函数.
  2. 相应的成员没有移动构造函数,在这种情况下将应用复制构造函数.

移动内置类型就像复制它们一样,即它们不会对移动的来源做任何事情,例如,std::unique_ptr<T>它会将空指针放入源中.

你用的时候

A b = std::move(a);
Run Code Online (Sandbox Code Playgroud)

a可以使用生成的移动构造函数给出一个可以移动构造的临时对象的外观A.不构造 rvalue-reference,而是简单地转换相同的对象.std::move(a)相当于static_cast<A&&>(a).


Jos*_*eld 5

A b = a;
Run Code Online (Sandbox Code Playgroud)

这是行不通的,因为它A是不可复制的。也就是说,因为 isa是一个左值表达式,所以它会尝试使用已delete创建的复制构造函数,因此无法编译。

A b = std::move(a);
Run Code Online (Sandbox Code Playgroud)

这会起作用,因为它A是可移动的。也就是说,因为std::move(a)是一个右值表达式,所以它将尝试使用defaulted 的移动构造函数,因此它将编译。

仅在第一种情况下才会尝试复制。第二个不涉及副本。仅仅因为b最终被构建,并不意味着它是从a. 相反,它已从a.