【问题标题】:Side effect c++ vector copy and deletion副作用c++向量复制和删除
【发布时间】:2014-05-22 12:51:49
【问题描述】:

我有这个问题:

void foo(vector<int> &a){
    vector<int> b;
    b.push_back(1); // in general many push backs
    a = b;
}

由于 b 是一个局部变量,它将在 foo 结束时被删除。 a 会保留 b 中插入的值吗? 我试过了,但可能只是偶然。

感谢您的帮助。

编辑:

我认为这回答了我的问题。不是吗? http://www.cplusplus.com/reference/vector/vector/operator=/ 所以基本上 a 将保留 c++98 中的值。但我无法完全理解它在 c++11 中的作用。

【问题讨论】:

  • 为什么不将push_back 转移到a
  • Jarod42 所说的。你也可以考虑a = std::move(b)。这将使分配更快,因为不需要副本,但代价是 b 之后包含垃圾,这很好,因为它无论如何都会死。
  • 如果对 a 的唯一修改是此分配,您可能需要考虑返回该向量。 -- a = foo(); 是一个比foo(a); 更容易被发现的副作用。

标签: c++ c++11 vector side-effects


【解决方案1】:

a = b 将调用std::vector复制赋值运算符。此运算符将向量的所有内容从b 复制到a,以便之后可以安全地删除b

考虑到您的编辑: 这个答案也适用于 C++11。 C++11 只增加了一个移动赋值运算符,但由于b 不是右值,所以不会调用这个运算符。

即使b 是一个 r 值(例如,通过将 b 包装到 std::move(b) 中),也会调用移动赋值运算符,这也可以。它将b 的内容移动到a,因此b 之后将是一个空向量,也可以安全删除。

【讨论】:

  • 编译器能否足够聪明地判断 b 将在之后被销毁,从而将其隐式转换为右值?
  • @galinette 只有当你返回它时(如果你返回一个类型与返回类型相同的本地非引用变量,就会发生这种情况)。
  • @galinette:在这种情况下,它可能足够聪明,但我不这么认为。无论如何,这种优化并不总是适用(例如,如果元素类型的构造函数或析构函数有副作用)。
  • @dyp:这并不完全正确。你的意思是复制省略。但是复制省略不是一个动作。它只是在调用者想要的地方构造返回值,所以既不复制也不移动到这里。
  • 不,我不是说复制省略。我的意思是 [class.copy]/32,而不是 /31:return 语句中的命名局部变量在某些情况下被视为右值。这是可能且安全的,因为在 return 语句之后不能引用局部变量。 另外,这个复制或移动可以省略。
【解决方案2】:

在 C++ 11 中发生的情况是,赋值运算符将进行复制,除非您使用 std::move 明确告诉它移动。

要强制移动,您可以这样做:

void foo(vector<int> &a){
    vector<int> b;
    b.push_back(1); // in general many push backs
    a = std::move(b);
}

为此,vector 已经为 move 实现了赋值运算符,如下所示:

vector<T>& vector<T>::operator =(vector<T>&& to_move) {}

当使用std::move 时,这告诉编译器使用已实现移动的重载函数,否则它将在未实现移动语义的旧版本上回退到const vector&lt;T&gt;&amp;

移动可能会更快,也可能不会更快,这取决于它是如何实现的,但是对于向量,您希望内部指针从旧向量移动到新向量,从而避免复制所有包含的对象。

例如

vector<T>& vector<T>::operator =(vector<T>&& to_move)
{
    delete [] m_ptrs;
    m_ptrs = to_move.m_ptrs;
    m_size = to_move.m_size;
    to_move.m_ptrs = nullptr;
    to_move.m_size = 0;
    return *this;
}

这当然是一个有根据的猜测,但希望它能证明使用移动语义时可能会发生什么。

【讨论】:

    【解决方案3】:

    如果这些值不是指针,它们将在a = b 中为copied,因此它们将被保留(当它们被插入http://www.cplusplus.com/reference/vector/vector/push_back/ 时,它们也会被先前复制到b)。

    如果是,它们也将被复制,但如果它们指向局部变量,您将获得大量无效指针。

    另一方面,如果它们是指向动态分配内存的指针,您不会发现任何问题。

    【讨论】:

      猜你喜欢
      • 2018-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-14
      • 2015-02-03
      • 2013-05-04
      • 1970-01-01
      • 2011-11-29
      相关资源
      最近更新 更多