填充std :: vector时的不同地址

时间:2013-08-13 09:58:07

标签: c++ vector initialization stdvector memory-address

您不希望两个循环打印的地址相同吗?我是,我无法理解为什么(有时)他们是不同的。

#include <iostream>
#include <vector>
using namespace std;

struct S {
  void print_address() {
    cout << this << endl;
  }
};

int main(int argc,char *argv[]) {
  vector<S> v;
  for (size_t i = 0; i < 10; i++) {
    v.push_back( S() );
    v.back().print_address();
  }
  cout << endl;
  for (size_t i = 0; i < v.size(); i++) {
    v[i].print_address();
  } 
  return 0;
}

我用许多本地和在线编译器测试了这段代码,我得到的输出看起来像这样(最后三个数字总是相同的):

0xaec010
0xaec031
0xaec012
0xaec013
0xaec034
0xaec035
0xaec036
0xaec037
0xaec018
0xaec019

0xaec010
0xaec011
0xaec012
0xaec013
0xaec014
0xaec015
0xaec016
0xaec017
0xaec018
0xaec019

我发现这是因为在第一个循环中进行了一些初始化,我在程序的后续部分中获得了未初始化的对象。我错过了什么吗?

4 个答案:

答案 0 :(得分:4)

因为当矢量capicity改变时,它会重新分配元素。如果std::vector::reserve有足够的容量,则不需要重新分配,它将打印相同的地址。

vector<S> v;
v.reserve(10);

注意:正确使用std::vector::reserve会提高应用程序性能,因为没有不必要的重新分配和对象复制。

答案 1 :(得分:2)

向量正在执行重新分配,以便根据需要增长。每次执行此操作时,它会为数据分配更大的缓冲区并复制元素。您可以在第一个循环中清楚地看到这一点,其中每个地址跳转后跟一个更大的连续地址序列。在第二个循环中,您只需在最终重新分配后查看地址。

0xaec010
0xaec031  <--
0xaec012  <--
0xaec013
0xaec034  <--
0xaec035
0xaec036
0xaec037
0xaec018  <--
0xaec019

使用10个S对象实例化向量的最简单方法是

std::vector<S> v(10);

这将不涉及重新分配。另请参阅std::vector::reserve

答案 2 :(得分:1)

矢量元素连续存储;也就是说,它们在记忆中都是连续的。矢量对象必须为这个连续的元素块分配空间。

你的矢量不能无限期地添加它。它必须增加它分配的空间。内存模型通常不允许我们扩展内存块 - 我们必须创建一个新内存块。当向量执行此操作时,它必须将其所有元素移动到新空间。这在你的第一个循环中发生了好几次。

如果你做完了:

vector<S> v;
v.reserve(10);

(你可以,因为你知道你最终会得到10个元素),所以不需要重新分配,地址也不会改变。

答案 3 :(得分:0)

我真的很惊讶他们可以改变。由于向量最初没有大小,因此在初始循环期间可能会重新分配向量一次或两次。这将改变矢量的基地址。调整大小后,你最终会使用你之前使用的地址(虽然我觉得有点令人惊讶。你确定地址的第一部分吗?)

如果你想确保它们不会改变,你需要在开始推送它之前添加v.reserve()