Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does vector<list<T>> guarantee that element addresses stay unchanged?

We all know that addresses of elements in vector<T> may change when we append more elements (due to resizing), while elements in list<T> remains at the same address.

The question is, what about vector<list<T>>? For example,

vector<list<T>> container;
// Insert some elements to container...
T* ptr = &(container[0].back());
// Insert more elements to container...

Can we assume that ptr stays valid?

Naively, I think it should, because when the vector resizes it should call the move constructor of list<T>, which should not copy/move individual elements. However, I don't know if the standard ensures this.

like image 873
jick Avatar asked Aug 31 '14 20:08

jick


People also ask

Why should you not store the address of an element in a vector?

You want to avoid taking the address of elements in a vector if at all possible precisely because of the unpredictable nature of reallocations. If you have to, use iterators instead of raw addresses, since checked STL implementations will tell you when they have become invalid, instead of randomly crashing.

Which is better vector or list?

Vector may have a default size. List does not have default size. In vector, each element only requires the space for itself only. In list, each element requires extra space for the node which holds the element, including pointers to the next and previous elements in the list.

When should I use vector instead of list?

If you don't need to insert elements often then a vector will be more efficient. It has much better CPU cache locality than a list. In other words, accessing one element makes it very likely that the next element is present in the cache and can be retrieved without having to read slow RAM.

Does vector have contiguous memory?

Vectors are assigned memory in blocks of contiguous locations. When the memory allocated for the vector falls short of storing new elements, a new memory block is allocated to vector and all elements are copied from the old location to the new location. This reallocation of elements helps vectors to grow when required.


2 Answers

Sorry, no. std::list's move constructor is not noexcept. std::vector used std::move_if_noexcept when doing resizes, which will be copies for the contained std::lists. All the list nodes will be allocated and copied. Their addresses will not be stable.

like image 68
Eric Niebler Avatar answered Sep 19 '22 13:09

Eric Niebler


You should probably make it a vector<list<T>*> rather than a vector<list<T>>. With a vector<list<T>*>, you can be certain that the contained pointers will not be changed (and that there won't be any heavy-weight copying of the inner lists) as they are values of the vector and the values of the vector are not changed by the expansion logic. This is much safer than relying on the copying of the internal lists to only move the head element and not reallocate any of the remaining nodes (it's also more understandable). Doing it the other way is difficult to understand and is just playing with fire.

like image 30
Michael Aaron Safyan Avatar answered Sep 20 '22 13:09

Michael Aaron Safyan