I get how vectors works in general as far as memory allocation is concerned, but what happens when you use a vector to store a vector of some simple type.
The simple solution is to always use pointers for the inner vectors, but then what's the difference between declaring something like "vector<vector<int>> a
" to declaring something like "vector<vector<int>*> b
"?
In the case where it's actually a contiguous block of memory for the inner vectors what happens when a reallocation breaks the boundaries of memory that could be used? Is everything copied to a new block? That seems unlikely because it's so expensive, but then it goes back to the question in the second paragraph.
Thanks for your time!
CodePudding user response:
A vector<vector<int>>
uses std::allocator
for both the outer and inner vectors. These are all independent allocations.
std::vector
supports custom allocators, and in particular it supports std::scoped_allocator_adaptor
to share an allocator across nesting levels. So you could write an allocator to try to keep things in contiguous memory. But as you already noted, there are limits to what you can achieve. For every allocator, there's always an allocation pattern that will fragment allocations.
CodePudding user response:
A vector<vector<T>>
is not a special case of std::vector
. There is no special allocation code that gets used when you use a vector<vector<T>>
. Every vector<T>
that you put into this vector<vector<T>>
manages its allocations by itself. The surrounding vector only manages the allocation that contains each vector<int>
itself (but not the allocations that they manage).
Concerning your second question, the difference between a vector<vector<T>>
and a vector<vector<T>*>
(I assume this is the kind of type you meant when you used the asterisk), is that the second one is a vector of pointers to vector of T
, while the first one is a vector of vectors of T
.
And just to emphasize, the memory managed by the inner vectors do not form one giant contiguous memory block.
It's worth pointing out though that std::vector
does have one special case for a particular type: std::vector<bool>
. Standard library implementations are encouraged by the standard to write it in such a way that when you use std::vector<bool>
, it only stores 1 bit for each bool
, instead of a full byte. This can reduce memory usage, at the cost of a tiny bit of runtime efficiency, since you now need extra instructions to extract individual bits whenever you access elements of that vector. vector<bool>
is also sometimes annoying in template metaprogramming, since its methods are actually slightly different from the normal std::vector
. I hope this gave some insight.