通过预留和复制还是创建和交换,哪种方法复制向量更有效?

177

我正在尝试高效地复制一个向量。我看到有两种可能的方法:

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;
}
哪种方法更好,为什么?我正在寻找最高效的解决方案,以避免不必要的复制。

14
第二个名称有误导性——因为它不是一个复制品(尽管它很快)。 - Anonymous
6个回答

283

但它们并不相同,是吗?一个是复制,另一个是交换。因此这两个函数有不同的名称。

我最喜欢的是:

a = b;

其中ab是向量。


3
实际上,这种方法是通过值传递的,编译器调用复制构造函数,然后交换新创建的元素。这就是为什么rlbond建议直接调用复制构造函数以达到相同的效果。 - David Rodríguez - dribeas
1
然而,如果没有传递原始值的函数调用rlbon,则无法调用它。否则,原始值将为空。第二种解决方案确保您始终按值调用,因此您不会丢失原始向量中的数据。(假设交换处理指针) - Eyad Ebrahim
这样做不会将b的元素移动到a中(使b的大小为0)吗? - Jonathan.
1
@Jonathan。假设你谈论的是a = b,那么不行。赋值意味着使a等于b而不改变b。相比之下,std::swap(a, b)会交换它们的内容(因此bsize现在将是以前a的大小),也许您正在考虑移动操作(如在C ++ 11中发生,但不是在普通分配中像这样)。这样的移动将保留b处于一种“有趣”的状态-请参见https://dev59.com/BmMm5IYBdhLWcg3wRdfe。 - Daniel Earwicker
1
@Jonathan。注意双和符号&&。该版本仅用于rvalue引用。它不会匹配任何非const值(例如上面示例中的b)。您可以通过说a = std::move(b);b转换为一个值。请参见http://en.cppreference.com/w/cpp/language/value_category,了解更高级别的复杂性。 - Daniel Earwicker
显示剩余5条评论

136

如果您按引用发送参数,则您的第二个示例不起作用。您是指

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

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

那种方法可以行得通,但更简单的方法是:

vector<int> new_(original);

很好,它可以工作。但是对于向量数组它不起作用:例如:vector<int> A[n]; - ABcDexter
11
这是“交换”,而不是“复制”。 - sdd
3
@sdd - 不是这样的。请检查参数列表。original 是函数参数的一个副本。 - rlbond
@rlbond 不小心 给回答点了踩 :(,您能否编辑一下帖子,这样我就可以取消踩赞并给予赞赏了吗? - Shubham Sharma

88

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

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

这比使用std::copy从头到尾遍历整个向量并将其插入新向量的std::back_insert操作甚至更简单。

话虽如此,你的.swap()方法不是复制,而是交换两个向量。 这会修改原始向量,使其不再包含任何内容!这不是一份复制。


1
更加灵活的方式是 a = b;,因为我已经有了成员字段 a,只需要将其赋值为来自 b 的新值。 - daparic

33

直接回答:

  • 使用=运算符

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

  • 使用构造函数

此外,构造函数也是有意义的。带有另一个向量作为参数(例如x)的构造函数构造了一个容器,其中每个元素的副本与x中的元素相同,并且顺序也相同。

注意:

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

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

  • 深拷贝还是浅拷贝?

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

根据维基百科:

深度复制是指对字段进行反引用:不是复制对对象的引用,而是为任何引用对象创建新的副本对象,并将对这些对象的引用放置在B中。

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

参考资料

cplusplus.com上的std::vector页面


23
new_vector.assign(old_vector.begin(),old_vector.end()); // Method 1
new_vector = old_vector; // Method 2

14

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

相反,应将原始向量作为参数传递给新向量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接