C++: 用整数移动语义

问题描述 投票:1回答:2
int c = 2;
int d = std::move(c);
std::cout << "c is: " << c << std::endl;
std::cout << "d is: " << d << std::endl;

此代码输出。

C是: 2

d是:2

我以为move(c)到d后,c会是空的,为什么它的值还是2?你们谁能帮我解释一下?谢谢你的帮助。

c++ c11
2个回答
4
投票

我以为move(c)到d后,c会是空的。

你的期望值被误导了。

为什么它的值还是2?

基本类型没有移动构造函数。你只是简单地复制了一个对象。复制不会修改源对象。


对于类类型来说,如果假设移动构造函数到底做了什么,具体让源对象处于什么状态,那就不安全了。不一定能保证它是 "空 "的。看类的文档就知道它的作用。如果没有文档,或者文档没有给出任何保证,那么你就不能对源对象的状态做出任何假设。


3
投票

std::move 不动任何东西! (与它的名字相反)。它完全等同于一个 static_cast 到一个 rvalue 引用类型。

它,只是一个投向rvalue的值--更具体地说,是投向一个 x值,而不是一个pr值。. 而且也确实,把投名状命名为move有时会让人感到困惑。然而这种命名的目的不是为了混淆,而是为了让你的代码更易读。

使用 xvalue,我们可以触发正确的过载,因此,我们可以使用 交换 来获取另一个对象的所有权(但不是必须的)。

例如,一个链接列表的移动构造函数可能会复制指向列表头部的指针,并将其存储在 nullptr 的参数中,而不是分配和复制单个节点。

为什么它的值还是2

如前所述 std::move 不动,而真正的交换移动资源的工作是由过载来完成的,如 调动构造师调任. std::move 任务只是为了抛出,以便编译器能够调用正确的重载(例如,移动构造函数,而不是复制构造函数),实际的资源移动必须由软件开发者在各自的重载中定义。因为,基本类型如 int 没有任何的移动构造函数,语句中的 int c = std::move(a); 只是复制了 ac.

试试这个。

#include <iostream>
#include <utility>


void hello(int& a)
{
    std::cout << "LVALUE" << std::endl;
}

void hello(int&& a)
{
    std::cout << "RVALUE" << std::endl;
}

int main(void)
{
    int a = 8;
    hello(a);
    hello(std::move(a));
    return 0;
}

0
投票

首先,正如@eerorika所提到的: 移动基本类型相当于复制。这种行为的原因非常清楚。Move语义是为了节省计算资源而开发的,而你通过清除一个不会被进一步使用的整数变量的值,显然什么都没有节省(而是浪费了一些东西)。放在那里是最好的。

其次,一个 "被移动 "的变量不一定是 "空 "或 "清空 "的。从形式上看,它可能处于任何状态,但对于标准库对象,有一些保证:(引自 此处)

除非另有规定,所有从标准库中移出的标准库对象都会被放置在一个有效但未指定的状态。也就是说,只有没有前提条件的函数,比如赋值运算符,才可以在对象被从

因此,你可能会看到一个 "被动的" std::vector 包含随机值,而且是完全正确的。千万不要认为这样的 std::vector 是(或不是)空的,因为它可能产生未定义的行为。更一般地,不要假设(除了状态对标准库对象有效外)一个对象的状态是从以下地方移来的。

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