2016-10-04 38 views
2

我用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 
+1

请添加正确的代码。 – SergeyA

+1

'(const auto&a:A){' - 那是什么? – SergeyA

+1

你为什么要存放地址?有向量中元素的引用永远有效(例如'vec [i]'为第i个元素) – user463035818

回答

3

迭代器(和引用对象不会忽略),不能保证当你调用vector<T>::push_back()被保存下来。如果新的size()大于当前的capacity(),则将发生重新分配并且将所有元素移动或复制到新位置。

为了避免这种情况,你可以叫你reserve()开始插入之前。

+0

亲爱的Krzaq,是的,你是对的,vec.reserve()运作良好。 Regards – cabe

+0

我不是'reserve()'方法的忠实粉丝,就好像稍后有人调用'push_back()'一样,它可能使指针的“世界”无效。 –

5

你是你for循环中调用vec.push_back(a)。因此,如果空间不足,向量可能会重新分配基础数组。因此,如果先前元素的地址被复制到新的内存位置,则其地址不再有效。

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

+0

亲爱的CopyKramer,是的,这是你的问题,谢谢你的回答。问候 – cabe

1

std::vector的主要特征之一是它的元素存储在连续内存(这对于访问现代CPU上的矢量项目时性能很好)。

的,不好的一面是,当为载体的预分配内存已满,并且要添加一个新的项目(如呼叫vector::push_back()),向量必须分配的连续存储另一块,和复制/将数据从前一个位置移动到新位置。作为重新分配和复制/移动的结果,旧项目的地址可能会改变。

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

例如,你可以使用shared_ptr同时为vector的项目和multimap的关键:

vector<shared_ptr<const A>> vec; 

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