【问题标题】:c++ std::move is bad here?c++ std::move 在这里不好?
【发布时间】:2016-02-22 10:08:13
【问题描述】:

假设我有 struct Foo 和 move constructoroperator=(Foo&&),我用它作为数据成员:

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?

并发现将return foo; 更改为return std::move(foo); 会导致RVO 禁用,但是(2) 会导致类似的情况吗?如果是这样,为什么?

【问题讨论】:

  • 复制省略无论如何都不适用于这种情况,因为您正在调用 foo.operator= 。如果你有 Foo foo = std::move(f()); 这是初始化,这将是相关的。
  • @M.M 但是clang 3.7 对此发出警告,所以我想知道是警告生成中的错误,还是我错过了什么
  • 它也可能因为非性能原因而变得糟糕。在你的#2 的情况下,你关心在已经是 rhr 的东西上调用 std::move(f()) ,所以移动是浪费字符。我的经验法则是你应该避免使用 std::move ,除非你必须这样做,而且只有在你以非平凡的方式转移所有权时才需要这样做。
  • 据我所知,std::move 的正确方法是在将数据传输到子程序时使用它,而不是从。但我也在等待答案;)
  • @Galik 你是对的,但如果 2 是明确告诉编译器移动的“坏”方法吗? (虽然它已经准备好移动了),如果是这样,为什么会不好?

标签: c++ c++11 move-semantics rvo


【解决方案1】:

这是多余且令人困惑的。仅仅因为我可以写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() 删除移动s 将值返回给operator= 的参数。

【讨论】:

  • 在第一个示例中,b 在由VS2013 编译时似乎并不悬空。 (尚未使用任何其他编译器进行测试)。您能否提供更多有关这方面的信息?
  • @DeanSeo clanggcc 都不会延长临时文件的生命周期。前者甚至会发出一些不错的性能警告。
  • @MatthäusBrandl 我不认为std::move(f()) 是临时的,但它可能很快就会作为一个xvalue 移动。所以它还没有移动......? (意思是不悬空)。我很久以前就发布了这个,所以也许我需要一些时间来赶上。
  • @DeanSeo 我意识到,但我想你可能会感兴趣。我猜在调用std::move() 之后,f() 的结果可能会在将引用传递给b 之前被合法破坏。似乎是一个评估顺序问题。
  • @MatthäusBrandl 哇,没想到!稍后我会更深入地了解这一点。
猜你喜欢
  • 2013-06-25
  • 2022-11-02
  • 2017-05-28
  • 1970-01-01
  • 1970-01-01
  • 2018-05-30
  • 2018-07-05
  • 1970-01-01
  • 2016-07-08
相关资源
最近更新 更多