简体   繁体   中英

Using map<int, Foo> instead of vector<Foo> to avoid pointer invalidation

Say I have a class Foo , and a container vector<Foo> Foos . The algorithms I use rely heavily on pointers to the elements of Foos , and I also need to add Foo s dynamically and to access elements of the container. The problem is that if I add too many elements to the vector, it may need to reallocate the elements, hence invalidating all the pointers to these elements. Would it make sense then to use something like map<int, Foo> instead of vector<Foo> ?

std::deque has similar performance (and random-access) to vector, but does not invalidate pointers upon insertion.

It does invalidate pointers on deletion, though.

我将使用std::vector<std::shared_ptr<Foo>> ,所以我仍然有一个向量,无论它们在向量中的位置如何,我仍然需要任何有效的指针。

This answer focuses on how to prevent pointer invalidation from happening, while still sticking to std::vector .

Preallocating

If you know beforehand the maximum number of Foo objects that the vector can contain, you can simply reallocate the vector's buffer with the std::vector::reserve() member function. This way, a reallocation of the objects won't happen and therefore the pointers to the Foo objects won't be invalidated.

Using a vector of pointers

Alternatively, you can use std::vector<std::unique_ptr<Foo>> instead of std::vector<Foo> . This way, even if the vector reallocates its elements, the address of the pointed Foo objects won't change since it will be the std:unique_ptr<Foo> objects the ones that will be reallocated, not the Foo objects. Therefore, the pointers to the Foo objects will still be valid.


The latter approach introduces an additional layer of indirection, and it is, therefore, less efficient than the former one.

You have four possibilities:

  • You use a non-invalidating container. That's your suggestion.

  • You reserve sufficient space in the vector beforehand ( El Professor's answer ). This only works when you know the maximum amount of Foo s in advance.

  • You use a vector of (smart) pointers ( Michael Chourdakis' answer ). This works as long as you do not need to use the pointers as iterators.

  • You make no change to your vector<Foo> , but instead of pointers, you make your algorithm work with indices. This allows you to look at the element before and after (after checking the vector bounds), and the indices won't be invalidated by reallocations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM