在C ++移动语义中似乎有很多错失的机会。我想了解这些背后的基本原理以及为什么标准在定义何时应该在以下情况下移动变量时不会更积极:
string f()
{
string s;
return s + " ";
}
我认为这是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!
}
g
使用移动语义将数据从s
移动到返回值,但h
无法编译,因为s
未在h
中移动}。我相信这是因为标准有g
的特殊情况,它基本上表示如果返回与返回类型完全相同类型的局部变量,则移动变量。为什么不是规则,如果你返回一个局部变量,它会被移动,无论其类型如何?
答案 0 :(得分:5)
我确信它可能需要一个移动示例,但是有人会想出另一个案例,他们认为s
最后一次被使用是“显而易见的”,因此应该移动
最终,您将拥有定义编译器需要执行的数据流分析的标准。作者决定保守地绘制这条线,以允许实现在这方面是愚蠢的。程序员总是可以编写std::move
来将副本更改为移动。
标准的另一种可能性是,如果代码不再使用它们,则说明对象是否被移动或复制是未指定的。这将使实现变得像它喜欢的那样聪明。我很确定这是一个坏主意:在实践中,用户通常不关心他们的对象是否被移动,但他们有时需要解决它。
答案 1 :(得分:2)
简单地说,这是当前标准中不必要的限制,这使得自动移动取决于复制省略的可用性。
另一个例子是:
struct X{
std::string s;
};
std::string foo(){
X x;
return x.s; // no automatic move
};
我在http://isocpp.org的未来标准提案论坛上打开了一个帖子,可以看到here。根据理查德史密斯的建议,我直接邮寄给迈克米勒关于在此问题上打开一个核心问题并得到了回应:
[...]根据理查德的上述摘要,它听起来像一个合理的问题,所以我将在问题列表的下一个版本中为它打开一个问题。感谢。
因此,对于C ++ 14,所有这些限制都可能会消失,每次返回本地变量时,您都会自动移动。
理查德的总结顺便说一下:
更具体地说,[class.copy] p31有一个规则,即可以为语句“return id-expression;”省略该副本。其中id-expression命名一个局部变量,并且该变量与函数的返回类型具有相同的cv-nonqualified类型。建议我们应该在任何时候有一个语句“return id-expression;”时执行自动移动。其中id-expression命名局部变量或函数参数,而不管变量的类型。