【问题标题】:Does std::vector::insert reserve by definition?std::vector::insert 根据定义保留吗?
【发布时间】:2016-05-23 09:36:10
【问题描述】:

当在std::vector 上调用insert 成员函数时,它会在“推回”新项目之前reserve 吗?我的意思是标准是否保证?

换句话说,我应该这样做吗:

std::vector<int> a{1,2,3,4,5};
std::vector<int> b{6,7,8,9,10};
a.insert(a.end(),b.begin(),b.end());

或者像这样:

std::vector<int> a{1,2,3,4,5};
std::vector<int> b{6,7,8,9,10};
a.reserve(a.size()+b.size());
a.insert(a.end(),b.begin(),b.end());

还是其他更好的方法?

【问题讨论】:

  • 这可能会回答你的问题:stackoverflow.com/questions/2208293/…
  • 这取决于迭代器是输入迭代器还是严格更强的迭代器。对于任何更强大的内容,您可以通过distance 获得计数。这是 QoI,但任何体面的实现都不应为此重新分配超过一次。
  • libstdc++libc++ 的实现如果至少给定前向迭代器,则立即为整个序列保留空间。
  • 附带说明:虽然insert会在内部调用reserve,但两种变体实际上可能会产生不同的汇编代码并导致不同的性能。

标签: c++ c++11 vector


【解决方案1】:

关于函数[link]的复杂度:

与插入的元素数量成线性关系(复制/移动构造) 加上位置(移动)之后的元素数。

另外,如果 InputIterator 在范围插入 (3) 中不是至少 前向迭代器类别(即,只是一个输入迭代器)的新 容量不能事先确定,并且插入会产生 大小的额外对数复杂度(重新分配)。

因此,有两种情况:

  • 可以确定新容量,因此您无需调用reserve
  • 无法确定新容量,因此调用reserve 应该很有用。

【讨论】:

  • 谢谢。有些东西我无法得到。这两种情况是实现可靠的。所以我应该深入研究我的编译器实现。或者它们是我应该根据我的代码预测它们的情况
  • 你应该预测一下情况。即如果你知道你会给输入迭代器更好的调用reserve之前。
【解决方案2】:

std::vector::insert 是否根据定义保留?

并非总是如此;取决于当前的容量。

来自草案 N4567,§23.3.6.5/1([vector.modifiers]):

如果新大小大于旧容量,则会导致重新分配。

如果vector 中分配的内存容量足以容纳新元素,则无需为vector 进行额外分配。所以不,那么它就不会保留内存。

如果vector 容量不够大,则分配一个新块,移动/复制当前内容并插入新元素。没有指定确切的分配算法,但通常会在 reserve() 方法中使用。

...还是其他更好的方法?

如果您在将元素插入vector 时担心分配过多,那么使用要添加的预期元素数量的大小调用reserve 方法确实可以最大限度地减少分配。

vector 是否在/任何插入之前调用reserve? IE。它是否在一次分配中分配了足够的容量?

没有保证。它如何知道输入迭代器之间的距离?鉴于insert 方法可以采用InputIterator(即单遍迭代器),它无法计算预期大小。 如果迭代器在其他地方(例如指针或RandomAccessIterator),该方法是否可以计算大小?是的,它可以。 吗?取决于实施和所做的优化。

【讨论】:

  • 你的意思是你的最后一段不能保证?它将并且将有零分配
  • @AlexeyAndronov。即使它有足够的空间,它也可以调用reserve,没有指定算法,所以理论上它可能希望分配更多作为缓冲区。
  • link: “当且仅当新向量大小超过当前向量容量时,这会导致分配的存储空间的自动重新分配。”
  • @AlexeyAndronov。标准中的措辞比这要弱。但重点是,我已经删除了注释。
【解决方案3】:

documentation看来:

如果新的 size() 大于旧的 capacity(),则会导致重新分配。

还要注意,在这种情况下,所有迭代器和引用都会失效。

不用说,重新分配负责insert,如果您当时查看这些操作,它是一个一致的 reserve-size-plus-one 操作在每个步骤中进行。
您可以争辩说,在发生不止一次重新分配的情况下,插入顶部的 reserve 调用会加快一切速度……嗯,对,它可能会有所帮助,但这主要取决于您的实际问题。

【讨论】:

  • OP 在问一些不同的问题:他想知道在插入之前是否进行了预保留。
  • 你的意思是如果它作为一个整体保留,知道要插入的对象的数量?很明显,插入以某种方式负责重新分配,因此您可以将其视为每个步骤的 reserve-size-plus-one 请求(好吧,从逻辑上讲,除了性能之外)。
  • 在我看来,OP 想知道在 insert 期间是否可能发生多次分配,以及(隐式)保留大小是否会大大超过实际大小。
  • 嗯...知道了,我想它是依赖于实现的,我以 libstdc++ 为例来了解它们是如何实现的。
  • 等等,我确实同意@Niall,元素的数量是未知的,因此向量可以尽最大努力减少重新分配,仅此而已......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
  • 1970-01-01
  • 2018-10-23
  • 2017-05-27
  • 1970-01-01
  • 2013-01-25
相关资源
最近更新 更多