使用向量 push_back 分配内存

Posted

技术标签:

【中文标题】使用向量 push_back 分配内存【英文标题】:Memory allocation with vector push_back 【发布时间】:2013-03-28 21:30:27 【问题描述】:

我今天学到了一些有趣的东西:如果我有一个标准向量 v 并且我运行如下代码:

std::vector<float> v;
for (int i = 0; i < 2; i++) v.push_back(2.);

如果我调用v[2],我不会遇到分段错误,因为operator[] 不进行边界检查。我得到了一些荒谬的小数字,但我很好奇 push_back 的默认行为是什么,以及溢出向量边界我应该期待什么。我认为它必须分配比下一个浮点数更多的空间。多少?这是标准中的,还是特定于编译器的?

【问题讨论】:

您应该期待未定义的行为。不多也不少。 尝试不优化编译,您的标准库实现可能在这种情况下对vector::operator[] 进行边界检查。无论如何,一旦边界检查被丢弃,您的代码就会出现未定义的行为。 您希望学到的(这是非常宝贵的一课)是未定义行为并不意味着您的程序会崩溃。它确实意味着它所说的,你的程序的行为是未定义的。尽管它很简单,但有些人对这个概念感到困惑。 如果你想检查边界,你可以使用vector::at。 v.at(n) 如果超出范围会抛出异常。 【参考方案1】:

我今天学到了一些有趣的东西

所以是时候学习一些更有趣的东西了:你的代码有Undefined Behavior,因为使用下标运算符的前提是索引小于大小向量。

根据 C++11 标准的表 101,表达式 a[n] 等效于 *(a.begin() + n)。由于v.begin() + 2 是容器v 之外位置的迭代器,因此取消引用它会导致未定义的行为。

【讨论】:

那么push_back在调用的时候会分配多少内存呢?是否足以容纳向量中包含的任何内容,还是依赖于编译器?我假设它不会为带有一个额外元素的向量重新分配内存、复制向量并每次释放。 @webb: 大多数时候,调用push_back() 根本不会分配内存——向量已经分配了一个连续的内存区域,这就是新元素将被推送的地方.但是,如果先前分配的内存已满且向量超出其容量,push_back() 将导致新分配一个足够大的连续内存区域以包含当前内容以及新元素 a一定数量(取决于实现)的其他元素。然后,向量的元素被移动到新分配的存储中。【参考方案2】:

如果我调用 v[2] 我不会遇到分段错误,因为 operator[] 不做边界检查

这两者没有关系...

您的代码调用未定义的行为,因此它可以做任何事情。

【讨论】:

以上是关于使用向量 push_back 分配内存的主要内容,如果未能解决你的问题,请参考以下文章

彻底销毁动态分配对象的向量

C++ Vector 实现分配新对象

3. 第 3 章 向量

如何预留多维向量?

改变向量内存分配策略?

释放分配给二维向量的内存