Pointers to elements of std::vector and std::list

一笑奈何 提交于 2019-11-26 19:59:43

问题


I'm having a std::vector with elements of some class ClassA. Additionally I want to create an index using a std::map<key,ClassA*> which maps some key value to pointers to elements contained in the vector.

Is there any guarantee that these pointers remain valid (and point to the same object) when elements are added at the end of the vector (not inserted). I.e, would the following code be correct:

std::vector<ClassA> storage;
std::map<int, ClassA*> map;

for (int i=0; i<10000; ++i) {
  storage.push_back(ClassA());
  map.insert(std::make_pair(storage.back().getKey(), &(storage.back()));
}
// map contains only valid pointers to the 'correct' elements of storage

How is the situation, if I use std::list instead of std::vector?


回答1:


Vectors - No. Because the capacity of vectors never shrinks, it is guaranteed that references, pointers, and iterators remain valid even when elements are deleted or changed, provided they refer to a position before the manipulated elements. However, insertions may invalidate references, pointers, and iterators.

Lists - Yes, inserting and deleting elements does not invalidate pointers, references, and iterators to other elements




回答2:


As far as I understand, there is no such guarantee. Adding elements to the vector will cause elements re-allocation, thus invalidating all your pointers in the map.




回答3:


Use std::deque! Pointers to the elements are stable when only push_back() is used.

Note: Iterators to elements may be invalidated! Pointers to elements won't.

Edit: this answer explains the details why: C++ deque's iterator invalidated after push_front()




回答4:


I'm not sure whether it's guaranteed, but in practice storage.reserve(needed_size) should make sure no reallocations occur.

But why don't you store indexes?
It's easy to convert indexes to iterators by adding them to the begin iterator (storage.begin()+idx) and it's easy to turn any iterator into a pointer by first dereferencing it, and then taking its address (&*(storage.begin()+idx)).




回答5:


Just make them both store pointers an explicitly delete the objects when you don't need them.

std::vector<ClassA*> storage;
std::map<int, ClassA*> map;

for (int i=0; i<10000; ++i) {
  ClassA* a = new ClassA()
  storage.push_back(a)
  map.insert(std::make_pair(a->getKey(), a))
}
// map contains only valid pointers to the 'correct' elements of storage



回答6:


From one of the comments to another answer, it seems as if all that you want is centralize (ease) memory management. If that is really the case, you should consider using prepackaged solutions like the boost pointer container library and keep your own code as simple as possible.

In particular, take a look at ptr_map




回答7:


  1. for vectors no.
  2. for lists yes. how? iterator works as a pointer to a particular node in the list. so you can assign values to any struct like:

    list mylist;

    pair< list::iterator ,int > temp;

    temp = make_pair( mylist.begin() , x );



来源:https://stackoverflow.com/questions/3287801/pointers-to-elements-of-stdvector-and-stdlist

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!