1

您不希望两个循环打印的地址相同吗?我是,我不明白为什么(有时)它们是不同的。

#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

4 回答 4

4

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

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

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

于 2013-08-13T10:00:13.810 回答
2

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

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

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

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

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

于 2013-08-13T10:01:14.620 回答
1

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

你的向量不能只是无限期地添加东西。它必须增加分配的空间。内存模型通常不允许我们扩展内存块——我们必须创建一个新的。当向量这样做时,它必须将其所有元素移动到新空间。这在您的第一个循环中发生了多次。

如果你做了:

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

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

于 2013-08-13T10:01:16.480 回答
0

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

如果您想确保它们不会更改,则需要v.reserve()在开始推送内容之前添加一个。

于 2013-08-13T10:05:16.873 回答