pop_back()能否减少向量的容量? (C ++)

时间:2014-05-20 16:00:20

标签: c++ c++11 vector capacity

根据C ++标准,std::vector<T>::pop_back()是否曾被允许降低向量的容量?

我在问,因为我想要保证,以下代码将抛出内存异常:

my_vec.pop_back();
if (...)
    my_vec.push_back(...);

假设my_vecstd::vector<int>

我猜有三种可能性:

  1. 是的,这可以根据C ++ 03和C ++ 11来实现。

  2. 不,C ++ 11禁止这样做(但C ++ 03没有)。

  3. 不,C ++ 03和C ++ 11都禁止这样做。

  4. 是的,我的问题与Does std::vector.pop_back() change vector's capacity?有关,但我的问题是关于标准保证的内容。

    另请注意,Does std::vector.pop_back() change vector's capacity?中接受的答案主要是关于如何降低向量的容量,而不是关于何时保证发生,并且没有提供任何证据声称关于pop_back()。

3 个答案:

答案 0 :(得分:8)

根据http://en.cppreference.com/w/cpp/container/vector/pop_back

  

除了back()end()之外,没有任何迭代器或引用无效。

因此可能无法重新分配。该页面上没有C++11标签,这意味着03年也是如此。我将挖掘部分参考并编辑它们以保证完整性。

修改:更好:来自C++03:[lib.container.requirements](23.1),第10段:

  

没有erase()pop_back()pop_front()函数会抛出异常。

N3337(〜C++11)中23.2.1 / 10的措辞相同。

答案 1 :(得分:5)

没有。缩小向量容量的唯一方法是交换技巧,如here所示。还有我提到的C++11方式。

另外,正如ref所说:

  

移除向量中的最后一个元素,
      有效地将容器尺寸缩小了一个。

换句话说,它会更改矢量的大小 容量

查看迭代器有效性

  

结束迭代器和任何迭代器,指针和引用
      提到被删除的元素无效       参考其他的迭代器,指针和引用       未被删除的元素保证保留       指的是他们在电话会议之前提到的相同要素。

C++11中,您可以使用std::vector<>::shrink_to_fit()来更改容量(有关更多信息,请参阅第1个链接)。 (tnx Psyduck)。有趣的评论低于答案,但这个问题与上述方法无关,所以如果有兴趣,请阅读评论。

请注意,即使这种方法也不能保证减少capacity,因为ref说:

  

请求容器减小其容量以适应其大小。

     

请求是非绑定的,容器实现可以自由优化,否则&gt;并使向量的容量大于其大小。

     

这可能会导致重新分配,但对矢量大小没有影响,也无法改变其&gt;元素。

这个功能无法保证减少capacitypop_back,而第二个参考提及任何相关内容,这太奇怪了。

我看到它的方式,因为引用没有提及capacity,这意味着它不需要,这意味着capacity保持不变。

一个有趣的例子是:

#include <iostream>
#include <vector>

int main() {
  const int N = 1000000;

  std::vector<int> v1;
  v1.reserve(N);
  for (int i = 0; i < N; ++i) {
    v1.push_back(i);
  }

  std::cout << v1.capacity() << " and size = " << v1.size() << std::endl;

  for (int i = 0; i < N - 2; ++i) {
    v1.pop_back();
  }

  std::cout << v1.capacity() << " and size = " << v1.size() << std::endl;

  return 0;
}

输出:

1000000 and size = 1000000
1000000 and size = 2

capacity显然没有减少。

[编辑]

另一个相关的question,也可以被标记为重复,有一些很好的答案。以下是一些有趣的内容:

1)

  

去看看Scott Meyers Effective STL第17项。(OP看起来有些参考)   基本上你不能直接减少std :: vector的存储大小。 “技巧”是指&gt;创建一个合适大小的新容器,复制数据并与当前容器交换。

2)

  

不,你不能在没有复制的情况下减少矢量的容量。

3)

  

我不是说GCC没有一些方法可以在没有副本的情况下做你想做的事,&gt;但实现(我认为)会很棘手,因为向量需要使用Allocator对象来分配和释放内存,而Allocator的接口不包含reallocate()方法。我不认为这是不可能的,但它可能会很棘手。

我建议阅读更多链接。

[EDIT.2]

question也支持:

问:pop_back()可以减少capacity吗?

答:

如果您不能依赖适当的方法来减少容量(就您在标准中所读到的内容而言),您不能指望pop_back()做类似的事情。

答案 2 :(得分:1)

评论并没有真正解决它。显然,如果禁止std :: vector使用除std :: allocator之外的任何东西,并且如果禁止使用其他方法扩展std :: allocator,则无法使用相同的基址进行大小调整,这使得无法减少容量,因为迭代器将失效。

关于重新分配的最近信息是关于Why is there no reallocation functionality in C++ allocators?的stackoverflow评论

&#34;在某些情况下,没有什么能阻止std :: vector执行此操作(例如,它使用标准分配器知道它)。允许标准库使用底层系统的知识。 - KeithB Jun 23&#39; 10 at 21:39&#34; (但没有提到参考文献)

已经提交了将realloc添加到std :: allocator的想法,但它们都被拒绝了:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1953.html

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2045.html

论文没有明确声明std :: allocator被禁止扩展std :: allocator,但是他们只是表明它并不需要。他们也没有明确声明禁止std :: vector使用对底层系统的API调用......所以也没有真正的信息。