考虑以下两种向vector
添加元素的方法std::vector<int> vi1(10,42), vi2;
vi2.insert(vi2.end(),vi1.begin(),vi1.end());
<OR>
std::copy(vi1.begin(),vi1.end(),std::back_inserter(vi2));
std::copy
版本看起来更干净,我不需要输入两次vi2
。但是,由于它是一个通用算法,而插入是一个成员函数,insert
是否能比std::copy
表现得更好,或者它做同样的事情?
我可以对自己进行基准测试,但我必须对每个模板类型的每个向量进行基准测试。有人做过了吗?
有一些细微的差别。在第一种情况(std::vector<>::insert
)中,您为容器提供了一个范围,因此它可以计算距离并执行单个分配器以增长到最终所需的大小。在第二种情况下(std::copy
),该信息不直接出现在接口中,并且它可能会导致缓冲区的多次重新分配。
请注意,即使需要多次重新分配,插入的平摊代价仍然必须是恒定的,所以这并不意味着代价会渐近变化,但可能很重要。还请注意,该库的一个特别智能的实现具有使第二个版本同样高效所需的所有信息,通过专化std::copy
的行为来专门处理回插入迭代器(尽管我没有检查是否有任何实现实际上做到了这一点)。
您可能会认为vector::insert
可能能够优化一次插入多个项目的情况,但这比看起来要困难。例如,如果迭代器是输出迭代器呢?没有办法提前知道要执行多少插入操作。很可能insert
的代码只是像back_inserter
一样执行多个push_back
。
vector::insert
在大多数情况下可能会在c++标准库的大多数主流实现中表现得更好。原因是vector
对象具有当前分配的内存缓冲区的内部知识,并且可以预先分配足够的内存来执行整个插入,因为可以使用随机访问迭代器提前计算元素的数量。然而,std::copy
和std::back_inserter
将继续调用vector::push_back
,这可能会触发多次分配。
例如,libstdc++中std::vector::insert
的GNU实现,如果迭代器类别为RandomAccessIterator
,则提前预分配缓冲区。对于输入迭代器,vector::insert
可能等同于std::copy
,因为不能提前确定元素的数量。
不等同于std::copy
。它在某种意义上相当于push_back
。
是的,std::back_inserter
做同样的事情,如果您使用std:front_inserter
,您可以使用std::copy
,它也可以在前面插入(尽管您不能与std::vector
一起使用)。如果使用std::inserter
,它也可以在指定的迭代器上插入。因此,您可以看到,std::copy
根据您传递的第三个参数执行操作。
insert
,因为它可以执行得更好,因为它可以发现要插入的元素的数量,因此它可以一次分配那么多内存(如果需要的话)。在您的情况下,它可能会执行得更好,因为v1
是std::vector
,这意味着很容易在O(1)时间内计算元素的数量。