我的对象在矢量中的地址改变了

The address of my object in a vector changes

本文关键字:地址 改变 对象 我的      更新时间:2023-10-16

我用A对象填充了一个向量,然后将这些对象的地址存储在一个multimap中[1],但是打印消息显示存储在向量中的对象的引用发生了变化[2]。你知道为什么吗?以及如何避免任何更改。

//[1]
vector<A> vec; 
multimap<const A*, const double > mymultimap;
for (const auto &a : A) {
  double val = a.value();
  vec.push_back(a);
  mymultimap.insert(std::pair<const A*, const double >( &vel.back(), val)); 
  // displaying addresses while storing them    
  cout<<"test1: "<<&vec.back()<<endl;
}
//[2]
// displaying addresses after storing them
for(auto &i : vec)
    cout << "test2: " << &i <<endl;

结果:

test1: 0x7f6a13ab4000  
test1: 0x7f6a140137c8  
test2 :0x7f6a14013000  
test2 :0x7f6a140137c8  

您在for循环中调用vec.push_back(a)。因此,如果vector耗尽了空间,它可能会重新分配底层数组。因此,如果先前的元素被复制到新的内存位置,它们的地址将不再有效。

例如,你分配了3个元素并存储了它们的地址。在推回第四个元素后,向量必须重新分配。这意味着前3个元素将被复制到一个新的位置,然后第4个元素将在此之后添加。因此,您存储的前3个地址现在无效。

在调用vector<T>::push_back()时不能保证保留迭代器(以及引用和对象地址)。如果新的size()大于当前的capacity(),将发生重新分配,所有元素被移动或复制到新的位置。

为了避免这种情况,可以在开始插入之前调用reserve()

std::vector的主要特性之一是它将元素存储在连续内存中(当您在现代cpu上访问vector的项时,这对性能非常有利)。

的缺点是,当预分配的内存为向量是满的,你想要添加一个新的项目(例如调用vector::push_back()),向量必须分配另一块连续内存,并复制/移动数据从以前的位置到新的。由于这种重新分配和复制/移动的结果,旧项的地址可能会改变。

如果出于某种原因想要保留对象的地址,而不是将这些对象的实例存储在std::vector中,您可以考虑使用指向对象的指针向量。在这种情况下,即使在重新分配之后,对象指针也不会改变。

例如,您可以将shared_ptr用于vector的项和multimap的键:

vector<shared_ptr<const A>> vec;
multimap<shared_ptr<const A>, const double> mymultimap;