为何std::vector内部对象的地址会发生变化?
关于std::vector对象地址变化的疑问
测试代码
// Example program #include <iostream> #include <string> #include <vector> struct Foo { int value = 0; }; int main() { std::vector<Foo> objs; for (int idx = 0; idx < 5; idx++) { objs.push_back(Foo{.value = idx}); std::cout << "address: " << &(objs.back()) << "\n"; } std::cout << "=======\n"; for (const auto& obj: objs) { std::cout << "address: " << &(obj)<< "\n"; } }
问题描述
原本以为前后两次循环打印的对象地址应该完全一致,但实际运行后发现并非如此(第一次循环的地址会出现跳跃,第二次循环的地址是连续且稳定的)。该如何理解这种现象?是否是std::vector类在内部对对象进行了移动/重定位?
解答
这完全是std::vector的扩容机制导致的,核心原因在于它的底层实现是连续内存数组:
- 当调用
push_back添加元素时,如果当前vector的容量(capacity())不足以容纳新元素,会自动触发扩容:分配一块更大的新内存空间,把原内存里的所有对象拷贝/移动到新内存,然后释放旧内存。 - 第一次循环中,每次
push_back后立刻打印back()的地址,而每次扩容都会让之前的所有对象迁移到新地址,所以前几次打印的是旧内存地址,后续扩容后新元素的地址在新内存中,导致地址不连续;第二次循环是在所有元素添加完成后执行的,此时vector的容量已经足够,所有对象稳定存放在最终的连续内存块中,所以打印的地址连续且一致。 - 可以在循环中加入
std::cout << "capacity: " << objs.capacity() << "\n";,直观看到每次扩容时容量的变化,对应地址的跳转。 - 如果想要避免这种地址变化,只需在添加元素前调用
objs.reserve(5);预分配足够的容量,push_back过程中就不会触发扩容,前后两次打印的地址会完全一致。
内容的提问来源于stack exchange,提问作者firstprayer
相关产品推荐
相关产品推荐

