关于c ++:插入到底是否等同于std :: copy()?

Is inserting in the end equivalent to std::copy()?

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

1
2
3
4
5
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更好,或者它做的是相同的事情?

我可以自己做基准测试,但是我必须为每种模板类型的每一个向量做基准测试。有人做过吗?


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

请注意,即使需要多次重新分配,插入的摊余成本也必须保持不变,因此这并不意味着渐进的成本变化,但可能很重要。还要注意的是,库的一个特别智能的实现具有所有必需的信息,通过专门化std::copy的行为来专门处理back-insert迭代器,从而使第二个版本具有同样的效率(尽管我没有检查是否有任何实现真正做到这一点)。


您可能认为vector::insert可以优化一次插入多个项目的情况,但这比看起来要困难。例如,如果迭代器是输出迭代器,那么会怎样呢?没有办法提前知道要执行多少插入操作。很可能insert的代码只是多个push_backback_inserter相同。


在大多数情况下,EDCOX1〔11〕可能在C++标准库的主流实现中表现更好。原因是vector对象对当前分配的内存缓冲区有内部知识,并且可以预先分配足够的内存来执行整个插入,因为可以使用随机访问迭代器提前计算元素的数量。但是,std::copystd::back_inserter将继续调用vector::push_back,这可能会触发多次分配。

例如,在libstdc++中,std::vector::insert的GNU实现在迭代器类别为RandomAccessIterator的情况下预先分配缓冲区。对于输入迭代器,vector::insert可能等同于std::copy,因为您不能预先确定元素的数量。


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

是的,std::back_inserter做了同样的事情,你用std::copy也可以在前面插入,如果你用std:front_inserter(虽然你不能用std::vector)。如果使用std::inserter,它也可以在指定的迭代器中插入。所以你看,std::copy是根据你作为第三个论点所传递的东西来做的。

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