【问题标题】:Is it more efficient to copy a vector by reserving and copying, or by creating and swapping? [duplicate]通过保留和复制,还是通过创建和交换来复制向量更有效? [复制]
【发布时间】:2010-10-13 06:44:00
【问题描述】:

我正在尝试有效地制作矢量的副本。我看到了两种可能的方法:

std::vector<int> copyVecFast1(const std::vector<int>& original)
{
  std::vector<int> newVec;
  newVec.reserve(original.size());
  std::copy(original.begin(), original.end(), std::back_inserter(newVec));
  return newVec;
}

std::vector<int> copyVecFast2(std::vector<int>& original)
{
  std::vector<int> newVec;
  newVec.swap(original);
  return newVec;
}

哪些是首选,为什么?我正在寻找能够避免不必要的复制的最有效的解决方案。

【问题讨论】:

  • 第二个名字有误导性 - 因为它不是副本(虽然它很快)。

标签: c++ algorithm vector stl


【解决方案1】:

但它们不一样,是吗? 一个是副本,另一个是交换。因此函数名称。

我最喜欢的是:

a = b;

其中ab 是向量。

【讨论】:

  • 实际上方法是按值传递,编译器调用复制构造函数,然后交换新创建的元素。这就是为什么 rlbond 建议直接调用复制构造函数来达到同样的效果。
  • 但是,如果没有将原始函数作为 val 传递的函数,则不能调用 rlbon。否则,原来的将是空的。第二种解决方案确保您始终按值调用,因此您不会丢失原始向量中的日期。 (假设交换处理指针)
  • 这不会将 b 的元素移动到 a (使 b 的大小 == 0)吗?
  • @Jonathan。假设您在谈论a = b,那么不会。赋值意味着:使a等于b而不改变b。相比之下,std::swap(a, b) 将交换它们的内容(所以 bsize 现在将是 a 之前的任何内容)。您可能正在考虑移动操作(如在 C++11 中发生的那样,但不是像这样的普通赋值)。这样的举动将使b 处于一种“有趣”的状态——见stackoverflow.com/questions/17730689/…
  • @Jonathan。请注意双 & 符号 &amp;&amp;。该版本将仅用于右值引用。它不会匹配任何非常量值(例如上面我的示例中的b)。您可以通过说a = std::move(b);b 变成一个en.cppreference.com/w/cpp/language/value_category 以了解更高级别的复杂性。
【解决方案2】:

如果您通过引用发送参数,则您的第二个示例不起作用。你是说

void copyVecFast(vec<int> original) // no reference
{

  vector<int> new_;
  new_.swap(original); 
}

这可行,但更简单的方法是

vector<int> new_(original);

【讨论】:

  • 很好,它有效。但它不适用于向量数组:例如:vector A[n];
  • 那是交换,不是复制。
  • @sdd - 不,不是。检查参数列表。 original 是函数参数的副本。
  • @rlbond 不小心 否决了答案 :(,您能否编辑帖子,以便我删除不赞成票并投赞成票?
【解决方案3】:

这是制作向量副本的另一种有效方法,只需使用其构造函数即可:

std::vector<int> newvector(oldvector);

这甚至比使用std::copy 将整个向量从头到尾遍历到std::back_insert 他们进入新向量更简单。

话虽如此,您的.swap() 不是副本,而是交换了两个向量。您将修改原始文件以不再包含任何内容!这不是副本。

【讨论】:

  • 对我来说更灵活的是a = b;,因为我已经有成员字段a,我只需要使用b中的新值来分配它
【解决方案4】:

直接回答:

  • 使用= 运算符

我们可以使用容器std::vector 的公共成员函数std::vector::operator= 将值从一个向量分配给另一个。

  • 使用构造函数

此外,构造函数也很有意义。以另一个向量作为参数的构造函数(例如 x)构造一个容器,其中包含 x 中每个元素的副本,顺序相同。

注意:

  • 不要使用std::vector::swap

std::vector::swap 不是复制一个向量到另一个向量,它实际上是交换两个向量的元素,正如它的名字所暗示的那样。换句话说,要复制的源向量在调用std::vector::swap 之后被修改,这可能不是您所期望的。

  • 深拷贝还是浅拷贝?

如果源向量中的元素是指向其他数据的指针,那么有时需要深拷贝。

根据维基百科:

深拷贝,意味着字段被取消引用:不是对被复制对象的引用,而是为任何被引用的对象创建新的复制对象,并将对这些对象的引用放在 B 中。

实际上,目前 C++ 中并没有内置的方式来进行深度复制。上面提到的所有方法都是肤浅的。如果需要深拷贝,您可以遍历向量并手动复制引用。或者,可以考虑使用迭代器进行遍历。关于迭代器的讨论超出了这个问题。

参考文献

The page of std::vector on cplusplus.com

【讨论】:

    【解决方案5】:
    new_vector.assign(old_vector.begin(),old_vector.end()); // Method 1
    new_vector = old_vector; // Method 2
    

    【讨论】:

      【解决方案6】:

      你不应该使用 swap 来复制向量,它会改变“原始”向量。

      将原来的作为参数传递给新的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-01-30
        • 1970-01-01
        • 1970-01-01
        • 2022-12-16
        • 2012-12-13
        • 1970-01-01
        • 1970-01-01
        • 2022-08-03
        相关资源
        最近更新 更多