65

可能重复:
什么是移动语义?

我最近参加了一个 C++11 研讨会,并给出了以下建议。

when you have && and you are unsure, you will almost always use std::move

谁能向我解释为什么你应该使用std::move而不是一些替代品和一些你不应该使用的情况std::move

4

4 回答 4

97

首先,我要解决的问题可能存在误解:
每当您T&& t在代码中看到(并且 T 是实际类型,而不是模板类型)时,请记住值类别t是左值(引用),而不是右值(临时)不再。这很令人困惑。唯一的T&&意思t是从一个右值1的对象构造,但它本身是一个左值,而不是一个右值。如果它有名称(在这种情况下为),那么它是一个左值并且不会自动移动,但如果它没有名称( 的结果),那么它是一个右值,如果可以的话,它会自动移动到它的结果中。类型(在这种情况下t t3+4T&&) 几乎与变量的值类别(在本例中为左值)无关。

话虽这么说,如果您在代码中T&& t编写了代码,则意味着您引用了一个临时变量,如果您愿意,可以销毁。如果您需要多次访问该变量,您希望std::move从中访问,否则它将失去它的价值。但是,如果您愿意,最后一次访问它对另一个t人来说是安全的。(而且 95% 的时间,这就是你想要做的)。所有这些也适用于 变量。std::moveTauto&&

1.如果T是模板类型,T&&则改为转发引用,在这种情况下你使用std::forward<T>(t)而不是std::move(t)最后一次。看到这个问题

于 2013-01-23T18:26:19.583 回答
30

我发现这篇文章对一般的右值引用主题很有启发性。他在最后提到std::move。这可能是最相关的报价:

我们需要使用std::move, from <utility>--std::move是一种说法,“好吧,老实说我知道我有一个左值,但我希望它是一个右值。” std::move本身不移动任何东西;它只是将左值转换为右值,以便您可以调用移动构造函数。


假设您有一个如下所示的移动构造函数:

MyClass::MyClass(MyClass&& other): myMember(other.myMember)
{
    // Whatever else.
}

当您使用语句other.myMember时,返回的值是一个左值。因此代码使用复制构造函数来初始化this->myMember. 但由于这是一个移动构造函数,我们知道它other是一个临时对象,因此它的成员也是如此。所以我们真的很想使用更高效的移动构造函数来初始化this->myMember. Usingstd::move确保编译器将其视为other.myMember右值引用并调用移动构造函数,正如您希望的那样:

MyClass::MyClass(MyClass&& other): myMember(std::move(other.myMember))
{
    // Whatever else.
}

只是不要std::move在需要保留的对象上使用 - 移动构造函数几乎可以保证将传递给它们的任何对象弄脏。这就是为什么它们只用于临时的。

希望有帮助!

于 2013-01-23T18:34:16.833 回答
4

当你有T&&一个 rvalue 类型的对象时,这意味着这个对象可以安全地移动,因为以后没有其他人会依赖它的内部状态。

由于移动永远不会比复制更昂贵,因此您几乎总是想要移动它。要移动它,您必须使用该std::move功能。

什么时候应该避免std::move,即使它是安全的?我不会在琐碎的例子中使用它,例如:

 int x = 0;
 int y = std::move(x);

除此之外,我认为没有缺点。如果它不会使代码复杂化,恕我直言,应尽可能进行移动。

另一个你不想移动的例子是返回值。该语言保证返回值(至少)被移动,所以你不应该写

return std::move(x); // not recommended

(如果幸运的话,返回值优化命中,这甚至比移动操作更好。)

于 2013-01-23T18:18:26.710 回答
2

当您需要将对象的内容“转移”到其他地方时,您可以使用 move ,而无需进行复制。对象也可以使用 std::move 获取临时对象的内容而不进行复制。

阅读更多关于右值引用和从维基百科移动构造函数的信息。

于 2013-01-23T18:09:55.023 回答