在许多情况下,当从一个函数返回一个local时,RVO就起作用了。然而,我认为显式使用std::move至少会在RVO没有发生时强制移动,但RVO仍然会在可能的情况下应用。然而,情况似乎并非如此。
#include "iostream"
class HeavyWeight
{
public:
HeavyWeight()
{
std::cout << "ctor" << std::endl;
}
HeavyWeight(const HeavyWeight& other)
{
std::cout << "copy" << std::endl;
}
HeavyWeight(HeavyWeight&& other)
{
std::cout << "move" << std::endl;
}
};
HeavyWeight MakeHeavy()
{
HeavyWeight heavy;
return heavy;
}
int main()
{
auto heavy = MakeHeavy();
return 0;
}我用VC++11和GCC 4.71调试和发布(-O2)配置测试了这段代码。永远不会调用复制ctor。move ctor仅由调试配置中的VC++11调用。实际上,这些编译器看起来一切正常,但据我所知,RVO是可选的。
但是,如果我显式地使用move
HeavyWeight MakeHeavy()
{
HeavyWeight heavy;
return std::move(heavy);
}移动函数总是被调用。因此,试图让它变得“安全”只会让它变得更糟。
我的问题是:
std::move为什么要阻止RVO?std::move?或者,换句话说,如果没有应用RVO,我如何让编译器优化完成它的工作,同时仍然强制移动?发布于 2013-10-09 20:28:42
允许复制和移动省略的情况见标准(N3690版)的第12.8§31节:
当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用。在这种情况下,该实现将省略的复制/移动操作的源和目标简单地视为引用同一对象的两种不同方式,并且该对象的销毁发生在这两个对象在没有优化的情况下将被销毁的较晚时间。这种拷贝/移动操作的省略,称为拷贝省略,在以下情况下是允许的(可以组合起来以消除多个拷贝):
return语句中,当表达式是具有与函数返回类型相同的cv未限定类型的非易失性自动对象(函数或catch子句参数除外)的名称时,可以通过将自动对象直接构造到函数的返回值中来省略复制/移动操作的目标中,可以省略复制/移动操作
(我省略的两种情况指的是抛出和捕获异常对象的情况,我认为这对优化不太重要。)
因此,在return语句中,复制省略只能发生,如果表达式是局部变量的名称。如果您编写std::move(var),则它不再是变量的名称。因此,如果它应该符合标准,编译器就不能省略移动。
斯蒂芬T.Lavavej在Going Native 2013上谈到了这一点,并准确地解释了您的情况以及为什么要在这里避免std::move()。从38:04开始收看。基本上,当返回一个返回类型的局部变量时,它通常被视为一个右值,因此默认情况下允许移动。
发布于 2013-10-09 17:04:41
如果没有应用RVO,我如何让编译器优化完成它的工作,同时仍然强制执行move?
如下所示:
HeavyWeight MakeHeavy()
{
HeavyWeight heavy;
return heavy;
}将回报转化为行动是强制性的。
https://stackoverflow.com/questions/19267408
复制相似问题