将向量附加到向量的最佳方法[重复]

Posted

技术标签:

【中文标题】将向量附加到向量的最佳方法[重复]【英文标题】:Best way to append vector to vector [duplicate] 【发布时间】:2013-08-11 10:15:48 【问题描述】:
std::vector<int> a;
std::vector<int> b;
std::vector<int> c;

我想通过将bc 的元素附加到a 来连接这三个向量。哪种方法最好,为什么?


1) 使用vector::insert

a.reserve(a.size() + b.size() + c.size());
a.insert(a.end(), b.begin(), b.end());
a.insert(a.end(), c.begin(), c.end());
b.clear();
c.clear();

2) 使用std::copy

a.reserve(a.size() + b.size() + c.size());
std::copy(b.begin(), b.end(), std::inserter(a, a.end()));
std::copy(c.begin(), c.end(), std::inserter(a, a.end()));
b.clear();
c.clear();

3) 使用std::move(来自C++11):

a.reserve(a.size() + b.size() + c.size());
std::move(b.begin(), b.end(), std::inserter(a, a.end()));
std::move(c.begin(), c.end(), std::inserter(a, a.end()));
b.clear();
c.clear();

【问题讨论】:

我相信 move 是最好的选择,因为它也会“移动”对象,而不是在清除时调用复制构造函数和析构函数。 我看到您根据我的回答添加了对 reserve() 的调用... 是的,我添加了对 reverse() 的调用,以便彻底。 顺便说一句,std::back_inserter(a) 可能比std::inserter(a, a.end()) 更方便、更清晰。 我喜欢回答我在谷歌上搜索的问题的问题。感谢您提供源示例! 【参考方案1】:

在我看来,您的第一个解决方案是最好的方法。

vector&lt;&gt;::insert 旨在添加元素,因此它是最合适的解决方案。

您可以在目标向量上调用reserve 以保留一些空间,但除非您将大量向量添加在一起,否则它可能不会提供太多好处:vector&lt;&gt;::insert 知道将添加多少元素,您将避免只打一个reserve 电话。

注意:如果它们是更复杂类型的 vector(即自定义类,甚至是 std::string),那么使用 std::move 可以为您提供很好的性能提升,因为它将避免复制构造函数。但是,对于int 的向量,它不会给您带来任何好处。

注意 2:值得一提的是,使用 std::move 会导致您的源 vector 的内容无法使用。

【讨论】:

例如,在std::map&lt;int, My_Obj*&gt; 上使用std::move 来做到这一点?有什么好处吗? 不太可能,因为您的地图类型是基本类型之一:整数和指针。如果您的地图是std::map&lt;int, My_Obj&gt;(即,不是指向My_Obj 的指针),那么会有一些好处,前提是您的移动构造函数比复制构造函数更有效。【参考方案2】:

假设你想复制而不是移动,这将是最好的方法:

a.reserve(a.size()+b.size()+c.size()); // Reserve space first
a.insert(a.end(),b.begin(),b.end());
a.insert(a.end(),c.begin(),c.end());

如果你想搬家:

a.reserve(a.size()+b.size()+c.size()); // Reserve space first
a.insert(a.end(),std::make_move_iterator(b.begin()),
         std::make_move_iterator(b.end()));
a.insert(a.end(),std::make_move_iterator(c.begin()),
         std::make_move_iterator(c.end()));
b.swap(std::vector<int>()); // Clear and deallocate space
c.swap(std::vector<int>()); // Clear and deallocate space

更新:您已经多次编辑了您的问题,现在使它成为一个移动的目标。您的第一个选项现在与我的第一个建议非常相似。

更新 2:从 C++11 开始,您可能不再需要使用 “与空向量交换” 技巧来清除和释放空间,具体取决于您的图书馆对vector 的实现。以下可能会以更直观的方式完成这项工作:

// Empty the vectors of objects
b.clear(); 
c.clear();

// Deallocate the memory allocated by the vectors 
// Note: Unlike the swap trick, this is non-binding and any space reduction
//       depends on the implementation of std::vector
b.shrink_to_fit();
c.shrink_to_fit();

【讨论】:

在我的工作中,我使用了一个指针向量 (std::vector&lt;T_MY_OBJ*&gt;),我希望拥有良好的(避免内存泄漏问题)和安全的内存管理。 您的示例给出了一个整数向量。如果您有一个指针向量,您可能需要考虑使用 std::unique_ptrstd::shared_ptr 根据您的用例来保存它们,以便进行适当的清理。 +1 for make_move_iterator:如果您有以后不打算使用的数据,move 来自它。 std::vector 需要方便的函数 insert_back :) - 在第一个参数固定为 .end() 的位置插入 +1 std::vector::insert 的清晰度和分配性能与std::move 的每个元素性能之间的最佳折衷。【参考方案3】:

第一个是最好的选择,因为insert 可以在开始复制之前计算出它添加了多少元素并调整向量的大小以适应它。其他人没有这些信息,因此可能会在一些复制后最终调整大小,这会比开始调整大小或多次调整大小要慢。

但是,正如@michaelgoldshteyn 所暗示的那样,由于您要进行两次插入,因此您也可以自己调整数组的最终大小,这可能会节省一次调整大小。

【讨论】:

【参考方案4】:

如果你真的想将bc的数据附加到向量a中,你必须进行插入(实际上是你的1.):

a.reserve( a.size() + b.size() + c.size() ); // preallocate memory (see why)
a.insert( a.end(), b.begin(), b.end() );
a.insert( a.end(), c.begin(), c.end() );

取决于编译器std::copy(您的2.)通常应该一样快。

由于std::vector 在内存中始终是连续的,所以您不能只移动(如C++11 中定义的那样)并且如果您知道最终大小您有保留您的向量(这将避免不必要的向量重新分配)。但是,如果您真的担心性能,请将其设为三个 std::vector,并在您必须读取它们的数据时对其进行迭代。

【讨论】:

不确定迭代 3 个向量会更快。如果所有数据都打包到一个向量中,那么正如您所说,它们是连续的,并且访问连续内存的速度更快。但是,这对于我来说太多了。 @Xaqq:是的,实际上这取决于您将迭代数据多少次......如果只有一次,那么您应该让向量作为三个不同的向量;如果超过两次,则应合并它们。 嗯?他的第 2 和第 3 个解决方案也可以,他不必必须使用他的第一个解决方案。同样,他根本必须保留任何东西,这只是一种优化。即便如此,带有随机访问迭代器的std::vector::insert(就像std::vector 一样)可能无论如何都会进行适当的保留,导致初始保留避免整个操作的单个重新分配。 “由于 std::vector 在内存中必须始终是连续的,你不能只移动数据” - 当然,如果源向量随后被清除,元素可以被移动。跨度> @ChristianRau:既然他要求“最好的方法”,我给了他最优化的答案......因为他必须做不止一个插入,很可能会发生两次重新分配。当然你可以move,但不是C++11的意思(你不能使用你的第二个向量的分配内存作为你第一个向量的扩展):你很可能会移动通过复制省略。

以上是关于将向量附加到向量的最佳方法[重复]的主要内容,如果未能解决你的问题,请参考以下文章

将向量作为单独的新列附加到 data.table,向量回收单个值

通过for循环将值附加到向量不起作用

如何组合两个整数向量[重复]

将向量作为一行附加到 CSV 文件中

R - 如果列包含来自向量的字符串,则将标志附加到另一列

如何将向量附加为 R 矩阵中的列?