插入到底是等同于std :: copy()吗?

时间:2013-01-17 15:17:31

标签: c++ stl-algorithm

考虑以下两种方法将元素附加到向量

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是一个成员函数,insert可以比std::copy表现更好还是做同样的事情?

我可以自己做基准,但我必须为每个模板类型的每个向量执行此操作。有人做过吗?

4 个答案:

答案 0 :(得分:6)

有一些微妙的差异。在第一种情况下(std::vector<>::insert),您为容器提供了一个范围,因此它可以计算距离并执行单个分配器以增长到最终所需的大小。在第二种情况(std::copy)中,信息不直接出现在接口中,并且可能导致缓冲区的多次重新分配。

请注意,即使需要多次重新分配,插入的摊销成本仍必须保持不变,因此这并不意味着渐近的成本变化,但可能很重要。还要注意,库的一个特别智能的实现具有所有必需的信息,通过专门处理std::copy的行为来专门处理反向插入迭代器,使第二个版本变得高效(尽管我还没有检查任何实现是否实际执行此操作)。

答案 1 :(得分:1)

在大多数情况下,对于C ++标准库的大多数主流实现,

vector::insert可能会表现得更好。原因是vector对象具有当前分配的内存缓冲区的内部知识,并且可以预先分配足够的内存来执行整个插入,因为可以使用随机访问迭代器预先计算元素的数量。但是,std::copystd::back_inserter会一直调用vector::push_back,这可能会触发多次分配。

例如,如果迭代器类别为std::vector::insert,则libstdc ++中的RandomAccessIterator的GNU实现会预先分配缓冲区。对于输入迭代器,vector::insert可能等同于std::copy,因为您无法提前确定元素数。

答案 2 :(得分:1)

你会认为vector::insert可能能够优化一次插入多个项目的情况,但它比它看起来更难。如果迭代器是输出迭代器,那会怎么样 - 没有办法提前知道你要做多少次插入。 insert的代码可能只有多个push_backback_inserter相同。

答案 3 :(得分:0)

它不等同于std::copy。它相当于push_back(在某种意义上)。

是的,std::back_inserter执行与std::copy相同的操作,如果您使用std:front_inserter,也可以在前面插入(尽管您不能std::vector)一起使用。如果您使用std::inserter,它也可以在指定的迭代器中插入。所以你看,std::copy基于你作为第三个参数传递的内容做了什么。

现在回到问题的本质。我认为你应该使用insert,因为它可以更好地执行,因为它可能会发现要插入的元素的数量,因此它可以一次分配那么多内存(如果需要的话) )。在您的情况下,它可能会表现更好,因为v1std::vector,这意味着在O(1)时间内很容易计算元素的数量