【问题标题】:Why std::move didn't move为什么 std::move 没有移动
【发布时间】:2016-07-23 22:17:04
【问题描述】:

在vs13中写了如下代码:

std::vector<std::string> myvector(1000);
std::fill(myvector.begin(), myvector.end(), "Hello World");
std::vector<std::string> pushto;
for (auto s: myvector)
    pushto.push_back(std::move(*s));

工作但没有移动,它改为调用字符串复制ctor。 myvector 最后还有他的“Hello World”。 像这样使用常规的 c++ 98 迭代:

 std::vector<std::string> myvector(1000);
 std::fill(myvector.begin(), myvector.end(), "Hello World");
 std::vector<std::string> pushto;
 for (auto s = myvector.begin(); s != myvector.end();s++)
    pushto.push_back(std::move(*s));

实际上有效,并且调用了 move。 myvector 字符串为空。 为什么第一个更现代的符号不起作用?

【问题讨论】:

  • 第一个例子真的可以编译吗?我认为std::move(*s) 中不应该有*
  • 请注意,没有人说过移动应该删除原件。移动后,原件处于有效但未指定状态。即使您将&amp; 放在适当的位置,原始对象与新对象具有相同的值(即,在修改之前与以前相同)是完全有效的(并且,恕我直言,有时是需要的)。跨度>

标签: c++ c++11 visual-studio-2013


【解决方案1】:

在您的第一个示例中,您使用的是for (auto s: myvector),在这种情况下s 是当前迭代中值的副本。要完成您想要的,您应该通过参考来完成 - for (auto&amp; s: myvector)

请注意,字符串在std::move 之后不保证被清空,此调用只是将其参数转换为右值引用(&amp;&amp;)。对右值引用参数有重载的其他函数(例如 std::vector::push_back可能释放它们的 argumnet 资源。

【讨论】:

  • .. 即便如此,您也不能保证将旧字符串清空。
  • 确实,但这是使用std::move 的正确方法(它可能会在OP 的编译器中被清空,因为它在第二个示例中被清空了)
  • 正确的方式:当然,我同意你的看法。除了清空:这是编译器的类的实现细节(两者都不是)。
  • @orenshochat 您的欢迎 :) 如果此答案对您有帮助,您应该将其标记为已接受(使用绿色勾号 v)
【解决方案2】:

正如@Polikdir 所说,复制来自您在(auto s: myvector) 制作的副本。一种方法是使用 range-for 循环,使用&amp;&amp;(转发引用)或&amp;(正常引用):

for (auto & val : myvector)
    pushto.push_back(std::move(val));

不为人知,但有一种专门用于在容器之间移动对象的算法。其实也叫std::move

std::move(s.begin(), s.end(), std::back_inserter(pushto)); 

编辑:

q: 由于 std::move 只是强制转换为右值引用,它真的需要吗?在这种情况下,std::move 不是多余的吗? 不,因为变量(例如 val)不能是 r 值引用。这就是为什么我们需要在通用引用上调用std::forward&lt;T&gt;

另请注意:What does `auto && e` do in range-based for-loops?

【讨论】:

  • 因为std::move 只是转换为右值引用,真的需要吗? std::move 在这种情况下不是多余的吗?
  • 非常感谢,非常有帮助的解决方案
猜你喜欢
  • 1970-01-01
  • 2021-08-17
  • 1970-01-01
  • 2014-02-16
  • 2018-02-07
  • 1970-01-01
  • 2012-07-28
  • 2011-07-28
相关资源
最近更新 更多