I read that std::vector
should be contiguous. My understanding is, that its elements should be stored together, not spread out across the memory. I have simply accepted the fact and used this knowledge when for example using its data()
method to get the underlying contiguous piece of memory.
However, I came across a situation, where the vector's memory behaves in a strange way:
std::vector<int> numbers;
std::vector<int*> ptr_numbers;
for (int i = 0; i < 8; i++) {
numbers.push_back(i);
ptr_numbers.push_back(&numbers.back());
}
I expected this to give me a vector of some numbers and a vector of pointers to these numbers. However, when listing the contents of the ptr_numbers
pointers, there are different and seemingly random numbers, as though I am accessing wrong parts of memory.
I have tried to check the contents every step:
for (int i = 0; i < 8; i++) {
numbers.push_back(i);
ptr_numbers.push_back(&numbers.back());
for (auto ptr_number : ptr_numbers)
std::cout << *ptr_number << std::endl;
std::cout << std::endl;
}
The result looks roughly like this:
1
some random number
2
some random number
some random number
3
So it seems as though when I push_back()
to the numbers
vector, its older elements change their location.
So what does it exactly mean, that std::vector
is a contiguous container and why do its elements move? Does it maybe store them together, but moves them all together, when more space is needed?
Edit: Is std::vector
contiguous only since C++17? (Just to keep the comments on my previous claim relevant to future readers.)
std::vector
stored its items in contiguous memory. Unofficially it was contiguous, because there was a defect in the standard not stating it was contiguous. Then (if I recall), the defect was corrected in the 03 standard. – Timepleaserreserve
in advance. – Sneerstd::deque
withpush_back()
/emplace_back()
. – Bioclimatologynumbers.reserve(8);
just above your first "for" loop and you will stop seeing random numbers. – Diandianastd::array
. Of course now you loose the ability to freely resize like vector. The vector has to keep its data on the heap so that it can store a huge amount of data (much bigger than the stack), and grow when needed – Jaddacout << *ptr_number
so these are not addresses (it's dereferenced by the *). And if I was writing addresses (without the *) it would give me the previous addresses, not the ones the vector moved to. – Pledgee