C ++向量的insert和push_back差异


79

我想知道vectorpush_backinsert函数之间的区别是什么。

有结构上的差异吗?

在性能上有很大的不同吗?


4
insert可以在任何地方做,还包括范围支持等其他功能。push_back添加到末尾更方便。
克里斯,2012年

Answers:


93

最大的区别在于它们的功能。push_back总是在的末尾放置一个新元素,vectorinsert允许您选择新元素的位置。这会影响性能。vector元素仅在需要增加其长度时才在内存中移动,因为为其分配的内存太少了。另一方面,insert强制将所有元素移动到新元素的选定位置之后。您只需要为此放置一个位置。这就是为什么insert效率通常不如的原因push_back


9
另一方面,插入末尾的效率应与相同push_back
Matthieu M. 2012年

18
嗯,几乎一样有效-代码需要确定insert实际在处end(),因此进入的分支insert要比进入的分支多push_back,除非编译器可以确定实际上不需要它们。
Yakk-Adam Nevraumont 2012年

5
@TomerW人们选择C或C ++,以便能够sqeeze每一个机器周期就可以了,以提高性能,有时直接在ASM写点......每一个“如果”罪名,这是不是Java ..
塞萨尔

1
@Cesar这不是您选择语言的原因... cpp可以比c更快,反之亦然...地狱,在某些情况下,甚至Java对其运行时优化也可以比c更快。
Tomer W

@TomerW ho,为什么?请赐教。
塞萨尔(Cesar)

32

功能具有不同的用途。vector::insert允许您在中的指定位置插入对象vector,而vector::push_back只会将对象粘在最后。请参见以下示例:

using namespace std;
vector<int> v = {1, 3, 4};
v.insert(next(begin(v)), 2);
v.push_back(5);
// v now contains {1, 2, 3, 4, 5}

您可以使用insert作为执行相同的任务push_backv.insert(v.end(), value)


9

除了这样的事实,即push_back(x)不一样insert(x, end())(可能与性能稍好),有了解这些功能的几个重要的事情:

  1. push_back仅在BackInsertionSequence容器上存在-因此,例如,在上不存在set。之所以不能这样做,是因为push_back()它会始终将其添加到最后。
  2. 有些容器也可以满足FrontInsertionSequence并且它们满足push_front。这是可以满足的deque,但不能满足vector
  3. insert(x, ITERATOR)InsertionSequence,这是很常见的setvector。这样,您可以使用setvector作为多次插入的目标。但是,sethas具有insert(x)实际上执行相同操作的附加功能(此第一个插入操作set仅意味着通过从不同的迭代器开始加速在适当位置的搜索-这种情况下不使用此功能)。

关于最后一种情况,请注意,如果要在循环中添加元素,则执行container.push_back(x)container.insert(x, container.end())将有效地执行相同的操作。但是,如果您先得到container.end()它然后在整个循环中使用它,那将不是正确的。

例如,您可能会冒险以下代码:

auto pe = v.end();
for (auto& s: a)
    v.insert(pe, v);

这将以相反的顺序有效地将整个有效地复制avvector中,只有在您有幸没有重新分配用于扩展的vector时(您可以通过先调用来防止这种情况);如果您不太幸运,则会得到所谓的UndefinedBehavior(tm)。从理论上讲,这是不允许的,因为每次添加新元素时,矢量的迭代器都被视为无效。reserve()

如果您这样做:

copy(a.begin(), a.end(), back_inserter(v);

它将以原始顺序a在末尾进行复制v,并且不会带来迭代器失效的风险。

[编辑]我以前使这段代码看起来是这样,这是一个错误,因为它inserter实际上保持了迭代器的有效性和先进性:

copy(a.begin(), a.end(), inserter(v, v.end());

因此,此代码还将以原始顺序添加所有元素,而没有任何风险。


您关于std :: inserter被类矢量容器“冒险”的说法是不正确的。实际上,它旨在消除这些风险。没有反向顺序,没有未定义的行为。有关详细信息,请参见例如 fluentcpp.com/2017/10/06/stl-inserter-iterators-work
下坡

你是对的。我只是想使代码简短而不是将其扩展为扩展的手动循环,所以实际上不正确,因为这inserter保持了迭代器的先进性和有效性。我必须编辑帖子:)
Ethouris
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.