【问题标题】:Move with vector::push_back使用 vector::push_back 移动
【发布时间】:2012-07-19 08:03:40
【问题描述】:

假设我有以下代码:

#include <vector>
struct A {
    int a;
    int x;
};
int main() {
    using namespace std;
    A a1;
    A a2;
    vector<A> va;
    va.push_back(a1);
    va.push_back(move(a2));
}

我知道 std::vector 的元素是连续存储的,这与 std::list 不同。在上面的代码中a2 被移动了,但是真的没有将a2 复制到向量va 中吗? va.push_back(a2);va.push_back(move(a2));有什么区别?

【问题讨论】:

  • 在您的情况下,std::moveing a2 完全什么都不做,因为它是平面类型(即,它没有外部数据)并且仍然只是复制。
  • 您可能想阅读Can someone please explain move semantics to me? 了解移动语义的介绍。

标签: c++ c++11


【解决方案1】:

在您的情况下,没有有效的区别,因为您使用的是编译器提供的复制构造函数。使用可移动构造的对象时,您会看到明显的性能差异,并且需要花费大量精力来复制。在这种情况下,使用push_back(x) 会创建对象的副本,而push_back(move(x)) 会告诉push_back() 它可能会“窃取”x 的内容,从而使x 处于不可用且未定义的状态。

假设您有一个列表向量 (std::vector&lt;std::list&lt;int&gt; &gt;),并且您想要推送一个包含 100,000 个元素的列表。如果没有move(),将复制整个列表结构和所有 100,000 个元素。使用move(),一些指针和其他少量数据会被打乱,仅此而已。这会更快,并且需要更少的总内存消耗。

【讨论】:

  • 为什么? move c-tor 会自动生成,不是吗?
  • @ForEveR 是否自动生成并不重要,因为A 结构中没有可以移动的分配。您只有两个ints,移动构造函数将执行与复制构造函数相同的操作:将存储在源对象的整数中的值分配给新对象。这种类型的移动场景不可能优化,因为它已经达到了最佳状态。
  • @cdhowie 所以在移动过程中总是会复制一些东西?
  • @ggg:“move”不是某种让事情不会发生的灵丹妙药。 “移动”的作用是允许您在复制操作需要分配新内存等时指定所有权转移。如果你的副本不会做这样的事情,那么移动就没有什么帮助了。
  • @Thomas 可能。根据是否存在某些优化(例如小字符串优化),它可能不会更快 - 但不会更慢。但是请注意,在vec.push_back(move(str)) 之后,str 对象处于未指定状态。
【解决方案2】:

当你使用va.push_back(a2)时,版本vector&lt;T&gt;::push_back(const T&amp;)会被调用,当你使用va.push_back(move(a2))时,版本vector&lt;T&gt;::push_back(T&amp;&amp;)会被调用...

但在你的情况下,性能没有区别,因为

15 非联合类的隐式定义的复制/移动构造函数 X 执行其基和成员的成员复制/移动。

第 12.8 段 n3337 草案。

【讨论】:

    【解决方案3】:

    我想指出一些其他答案没有提到的东西;是?.push_back(move(?)) 在您的情况下会比?.push_back(?) 慢(当您有可复制的对象时),因为移动构造函数需要将移动的对象置零\设置移动的对象,这实际上是在编写\复制两个对象。

    【讨论】:

    • 移动构造函数不需要对移动对象执行任何操作。它不需要将任何东西归零,除非有需要重置为空的移动指针。 (编译器生成的移动构造函数不会将源对象归零。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-15
    • 1970-01-01
    • 1970-01-01
    • 2013-10-15
    • 2021-06-18
    • 2023-03-21
    相关资源
    最近更新 更多