为什么不能移动这些变量?

ano*_*ous 4 c++ move-semantics c++11

在C++移动语义中似乎有很多错失的机会.我想了解这些背后的基本原理以及为什么标准在定义何时应该在以下情况下移动变量时更积极:

string f()
{
    string s;
    return s + " ";
}
Run Code Online (Sandbox Code Playgroud)

operator+(const string&, const char*)不是operator+(string&&, const char*),我相信,因为这s是一个左值.难道标准不能说,在函数中最后一次使用局部变量时,变量是否可以被认为是可移动的?

我认为有一个类似的例子:

struct A { A(string&&); };
string g()
{
    string s;
    return s; // s is moved
}
A h()
{
    string s;
    return s; // s can't be moved!
}
Run Code Online (Sandbox Code Playgroud)

g使用移动语义将数据移动s到返回值,但h由于s未移入,因此不会编译h.我相信这是因为标准有一个特殊的情况g,它基本上说,如果你返回一个与返回类型完全相同类型的局部变量,则移动变量.为什么不是规则,如果你返回一个局部变量,它被移动,不管它的类型是什么?

Ste*_*sop 5

我敢肯定它可能需要移动任何一个例子,但是然后有人会想出另一个案例,他们认为这s是最后一次使用的"显而易见",因此应该移动.

最终,您将拥有定义编译器需要执行的数据流分析的标准.作者决定保守地绘制这条线,以允许实现在这方面是愚蠢的.程序员总是可以编写std::move以将副本更改为移动.

标准的另一种可能性是,如果代码不再使用它们,则说明对象是否被移动或复制是未指定的.这将使实现变得像它喜欢的那样聪明.我很确定这是一个坏主意:在实践中,用户通常不关心他们的对象是否被移动,但他们有时需要解决它.


Xeo*_*Xeo 2

简而言之,这是当前标准中不必要的限制,这使得自动移动取决于复制省略的可用性。

另一个例子是:

struct X{
  std::string s;
};

std::string foo(){
  X x;
  return x.s; // no automatic move
};
Run Code Online (Sandbox Code Playgroud)

我在http://isocpp.org的未来标准提案论坛上开了一个帖子,可以在此处查看。根据理查德·史密斯的建议,我直接向迈克·米勒发送了有关就此问题提出核心问题的邮件,并得到了以下回复:

[...]根据理查德上面的总结,这听起来确实是一个合理的问题,所以我将在问题列表的下一次修订中为其打开一个问题。谢谢。

因此,对于 C++14,所有这些限制可能都会消失,每次返回局部变量时,您都会自动移动。

顺便说一句,理查德的总结是这样的:

更具体地说,[class.copy]p31 有一个规则,即可以省略语句“return id-expression;”的副本。其中 id-表达式 命名一个局部变量,并且该变量具有与函数的返回类型相同的 cv-unqualified 类型。建议只要我们有“return id-expression;”语句,我们就应该执行自动移动。其中 id-表达式 命名局部变量或函数参数,无论变量的类型如何。