2015-11-20 100 views
5

让我们假设我有struct Foo与移动constructoroperator=(Foo&&),我用它作为数据成员:C++ std :: move在这里不好?

Foo f() 
{ 
    Foo foo; 
    //code 
    return foo; 
} 
struct Boo { 
Foo foo; 
Boo() { 
    foo = f();//1 
    foo = std::move(f());//2 
} 
}; 

如果(2)我其实并不需要std::move, 但如果我用在这里,这是否会造成不好的结果, 就像阻止优化一样?

我这样说的:Why does std::move prevent RVO?

,并找出改变RVOreturn foo;return std::move(foo);原因禁用,但对于(2)不会造成类似的情况?如果是这样,为什么?

+7

无论如何,复制elision不适用于这种情况,因为您正在调用'foo.operator ='。如果你有'Foo foo = std :: move(f());'这是初始化。 –

+1

@ M.M但是'clang 3.7'对此有所警告,所以我想知道,它是警告生成中的缺陷,还是我错过了一些东西 – user1244932

+1

由于性能原因,这可能是不好的原因。在你的情况#2,你关心调用std :: move(f())已经是rhr的东西,所以移动是浪费的字符。我的经验法则是,除非必须,否则您应该避免std :: move,并且您只需要在以非平凡方式转让所有权时。 – IdeaHat

回答

5

这是多余的和令人困惑的。仅仅因为我可以写std::add_pointer_t<void>而不是void*std::add_lvalue_reference_t<Foo>(或Foo bitand)而不是Foo&,并不代表我应该。

这也很重要在其他情况下:

auto&& a = f(); // OK, reference binding to a temporary extends its lifetime 
auto&& b = std::move(f()); // dangling 

等,如果Foo是什么,可以遍历,

for(const auto& p : f()) {} // OK 
for(const auto& p : std::move(f())) {} // UB 

而且在你的榜样,如果赋值运算符实现为复制和交换(operator=(Foo)),然后foo = std::move(f())强制执行不可移动的移动,而foo = f()可以将f()的返回值移至operator=的参数。

+0

在第一个例子中,''''编译'VS2013'时,'b'似乎不是悬而未决的。 (还没有用任何其他编译器测试过)。你能否提供更多关于这方面的信息? –

+0

@DeanSeo [clang](http://coliru.stacked-crooked.com/a/607b0d720af30b9e)和[gcc](http://coliru.stacked-crooked.com/a/698d5c5271c8f1c8)都不会延长暂时的。前者甚至会发出一些很好的性能警告。 –

+0

@MatthäusBrandl我不认为'std :: move(f())'是暂时的,但它可能会很快作为一个xvalue移动。所以它还没有移动...? (意思是不摇晃)。我很久以前发布了这个,所以也许我需要一些时间赶上。 –