8

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

我问是因为我想保证以下代码不会引发内存不足异常:

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

假设这my_vec是一个std::vector<int>.

我想有三种可能:

  1. 是的,这可以根据 C++03 和 C++11 发生。

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

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

是的,我的问题与std::vector.pop_back() 是否改变向量的容量有关?,但我的问题是关于标准保证的具体内容。

另请注意,Std::vector.pop_back() 中接受的答案是否改变了向量的容量?主要是关于如何减少向量的容量,而不是关于何时保证不会发生,并且没有提供任何证据证明它关于 pop_back() 的说法。

4

3 回答 3

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 的措辞相同。

于 2014-05-20T16:03:38.250 回答
5

不,缩小向量容量的唯一方法是交换技巧,如此处所示。还有C++11我在下面提到的方式。

此外,正如裁判所说:

删除向量中的最后一个元素,
有效地将容器大小减小一。

换句话说,它改变了向量的大小而不是它的容量

看看迭代器有效性

结束迭代器和引用被移除元素的任何迭代器、指针和引用
都无效。 引用其他未删除元素的
迭代器、指针和引用保证会继续 引用它们在调用之前引用的相同元素。

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

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

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

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

这可能会导致重新分配,但对向量大小没有影响,并且不能更改其 > 元素。

太奇怪了,这个函数不能保证减少capacity并且pop_back确实,而第二个的 ref没有提到任何相关的东西。

我看到它的方式,因为 ref 没有提到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

wherecapacity显然没有减少。

[编辑]

另一个相关的问题,也可以被标记为重复,有一些很好的答案。这里有一些有趣的:

1)

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

2)

不,您不能在不复制的情况下减少向量的容量。

3)

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

我建议阅读链接以获取更多信息。

[编辑.2]

这个问题也支持:

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

答:没有

当您不能依靠适当的方法来减少容量时(就您在标准中阅读的内容而言),您不能指望pop_back()这样做。

于 2014-05-20T16:03:44.990 回答
1

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

我能找到的关于重新分配的最接近的信息是关于为什么 C++ 分配器中没有重新分配功能的 stackoverflow 评论?说

“在某些情况下,没有什么能阻止 std::vector 这样做(例如,它知道它使用标准分配器)。允许标准库使用底层系统的知识。– KeithB 2010-06-23 21:39 "(虽然没有提到参考资料)

已经提交了将 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 调用......所以那里也没有真正的信息。

于 2014-05-21T08:41:09.327 回答