Why Shouldn't I Use vector<vector<vector<int>>>? - c++

I have just read a question regarding initializing multidimensional vectors (question) and Viktor Sehr and Sbi reccomended instead using a single vector and getting the element with my_vector[x+y*100+z*100*100]. Why is this? Is it for performance reasons? If so, how does it improve performance? Thanks in advance, ell.
Edit: Do these reasons still apply when the width/height/depth are not the same and can change?

Just few reasons:
It wastes spaces, it is slow (unpredictable memory access, cache waste, etc), it's cumbersome
Main performance drawback is likely to be caching. With flat arrays you are guaranteed memory to be contiguous - cache is happy. With vector of vectors - who knows!

This advice is sound if you're looking at a bottleneck here. If memory usage or speed of access of this vector are not critical, just go down the easiest road.
You should have a look at Boost.MultiArray which gives you best of both worlds.
If for whatever reason you cannot use Boost, I'd definitely typedef it:
typedef vector<vector<vector<int> > > My3DIntVector;
My3DIntVector v;

…Viktor Sehr and Sbi reccomended instead using a single vector and getting the element with my_vector[x+y*100+z*100*100]. Why is this?
Given the dimensions, it's logical recommendation if the sizes are fixed.
Is it for performance reasons? If so, how does it improve performance?
Consider:
the number of allocations required to create all arrays
the time to copy even one dimension
the complexity it adds to the system's allocator
the time it takes to free
the complexity of common operations, such as filling
Edit: Do these reasons still apply when the width/height/depth are not the same and can change?
Resizing this (massive!) array can be extremely slow. You have to understand how your program will operate if you want it to be fastest. The copy and destruction complexity of elements is also a consideration (when using something more complex than int). If you do a lot of resizing or insertions/deletions, then the flattened vector can be very slow.
However, if its dimensions are fixed, you can do much better than std::vector. std::array is one alternative. (If you go the route of std::array, be careful of what you allocate on the stack)

The only thing I can imagine is that this is one big block of memory and thus prevents from fragmented memory. This is much easier to cache.
A vector<vector<vector<int> > > contains a lot of chunks of memory: a chunk for the first vector, a chunk for each element in vector<> and a chunk for each element in the vector<vector<>>. This is not easy to cache and may produce hardly predictable memory usage.

Related

C++ Vector Memory

I'm working on a largish project, and we are having some memory issues now. Vectors have been used for all arrays, and a quick search there seems to be about 2000 member vectors.
Going through the code it seems nobody has ever used a reserve or a swap (were not on C++11 yet for this project).
Are there any tools or techniques I can do to find out how much memory is being lost in these vectors?
use valgrind for debugging memory issues.
http://valgrind.org/docs/manual/ms-manual.html
One fast but dirty trick to see the effect of capacity on memory would be to modify
std::vector (or typedef std::vector to your custom vector type).
Idea is to modify vector to ensure that this custom new vector increases capacity exactly by what is needed instead of doubling it (yes, it will be super slow), and see how memory usage of the application changes when you run it with this custom vector.
While not useful in actually optimizing the code, it at least quickly gives you an idea of how much you can gain by optimizing vectors.
Just add some periodic logging lines that print the vector size, capacity and
sizeof(v) + sizeof(element_type) * v.capacity();
for each of your vectors v (this last will be the exact size of the vector in memory). You could register all your vectors somewhere central to keep this tidy.
Then you can do some analysis by searching through your logfiles - to see which ones are using significant amounts of memory and how the usage varies over time. If it is only peak usage that is high, then you may be able to 'resize' your vectors to get rid of the spare capacity.

Initializing vector vector

I'm using a
vector<vector<size_t>> Ar;
structure. The contents of the structure change over time, and, in particular, the length of each of the nested vectors is random and changes in time. Order is important, and I cannot ignore the nested vector if it is empty. I know the maximum capacity of the nested vectors (say m) and outer vectors (say n).
I'm having some difficulty getting the initialization right. If I use
Ar(n);
there is no problem but I end up getting a memory fragmentation because the allocator does not know the size of nested vector. I would like to avoid this if possible, because I don't know what impact it will have as the size of the data I'm trying to handle increases. I try to get around the fragmentation by fixing the length of the nested vectors in advance to get a compact representation, but I'm having trouble doing this. I use
Ar(n,vector<size_t>(m));
but this is super slow and a massive waste of memory, because most of the entries will not be used.
I have successfully implemented this with a
vector<list<size_t> > Ar(n);
without suffering fragmentation, but it runs much slower than using a nested vector. A fixed representation such as a Boost::multi_array would take up too much space, for the same reason as the second initialization above, and it will be more difficult to implement because I would need to keep track of where the useful entries stop.
Any suggestions? Thanks in advance.
You don't know if memory fragmentation is a problem until you've profiled your code with a typical use case.
Unless m is very small in front of n, I think it won't be a bottleneck at all, since you still have mostly sequential memory accesses.
If you want to avoid it anyway, you could use reserve instead of resize or initialization with m objects. It will only allocate memory, without the overhead of constructing objects which will not be used, increasing initialization speed.
Moreover, reserveing capacity for the vectors will likely only consume virtual memory, not "real" memory, until you effectively use it.
And if you know the distribution of the inner vectors' size, use the mean value as the default length, it may help you reducing the waste of memory.
In any case, std::list is a bigger waste in space and a lot worse considering fragmentation.
Perhaps the resize function will help you. See here for details.

Variable sized char array with minimizing calls to new?

I need a char array that will dynamically change in size. I do not know how big it can get so preallocating is not an option. It could never get any bigger than 20 bytes 1 time, the next time it may get up to 5kb...
I want the allocation to be like a std vector.
I thought of using a std vector < char > but all those push backs seem like they waste time:
strVec.clear();
for(size_t i = 0; i < varLen; ++i)
{
strVec.push_back(0);
}
Is this the best I can do or is there a way to add a bunch of items to a vector at once? Or maybe a better way to do this.
Thanks
std::vector doesn't allocate memory every time you call push_back, but only when the size becomes bigger than the capacity
First, don't optimize until you've profiled your code and determined that there is a bottleneck. Consider the costs to readability, accessibility, and maintainability by doing something clever. Make sure any plan you take won't preclude you from working with Unicode in future. Still here? Alright.
As others have mentioned, vectors reserve more memory than they use initially, and push_back usually is very cheap.
There are cases when using push_back reallocates memory more than is necessary, however. For example, one million calls to myvector.push_back() might trigger 10 or 20 reallocations of myvector. On the other hand, inserting into a vector at its end will cause at most 1 reallocation of myvector*. I generally prefer the insertion idiom to the reserve / push_back idiom for both speed and readability reasons.
myvector.insert(myvector.end(), inputBegin, inputEnd)
If you do not know the size of your string in advance and cannot tolerate the hiccups caused by reallocations, perhaps because of hard real-time constraints, then maybe you should use a linked list. A linked list will have consistent performance at the price of much worse average performance.
If all of this isn't enough for your purposes, consider other data structures such as a rope or post back with more specifics about your case.
From Scott Meyer's Effective STL, IIRC
You can use the resize member function to add a bunch. However, I would not expect that push_back would be slow, especially if the vector's internal capacity is already non-trivial.
Is this the best I can do or is there a way to add a bunch of items to a vector at once? Or maybe a better way to do this.
push_back isn't very slow, it just compares the size to the current capacity and reallocates if necessary. The comparison may work out to essentially zero time because of branch prediction and superscalar execution on the CPU. The reallocation is performed O(log N) times, so the vector uses up to twice as much memory as needed but time spent on reallocation seldom adds up to anything.
To insert several items at once, use insert. There are a few overloads, the only trick is that you need to explicitly pass end.
my_vec.insert( my_vec.end(), num_to_add, initial_value );
my_vec.insert( my_vec.end(), first, last ); // iterators or pointers
For the second form, you could put the values in an array first and then copy the array to the end of the vector. But this might add as much complexity as it removes. That's how it goes with micro-optimization. Only attempt to optimize if you know there's a measurable gain to be had.

Should I worry about memory fragmentation with std::vector?

Should I worry about memory fragmentation with std::vector? If so, are there ways to help prevent it? I don't always predict for my programs to be running on a PC, they may also be running on embedded devices/game consoles, so I won't always be able to rely on virtual memory.
Then again I believe it would be more efficient to use a dynamically sized array rather than a static array, so that memory would only be allocated if needed. It would also simplify my programs' design process. Are there ways to achieve this efficiently?
Thanks for any advice!
The answer to your worries may be std::deque. It gives you a similar interface to that of std::vector, but works better with fragmented memory, since it allocates several small arrays instead of a large one. It is actually less efficient than std::vector in some aspects, but for your case it may be a good trade-off.
If your vector will be reallocated many times then yes, it can cause memory fragmentation.
The simplest way to avoid that would be using std::vector::reserve() if you more or less know how big your array can grow.
You can also consider using std::deque instead of vector, so you won't have problem with memory fragmentation at all.
Here is topic on stackoverflow which can be interesting for you: what-is-memory-fragmentation.
std::vector is only as good as new. It simply handles the underlying memory allocation for you
A couple of things you can do - assuming you don't want to write a whole new new handler.
Pre-allocate vectors or resize() if you know what eventual size they will be, this stops wasteful memory copies as they grow.
If you are going to be using the vector again with the same size, it's better to keep it and refill it than to delete it and recreate it.
Generally on embedded targets if you know the memory requirements it's best to statically allocate all the memory at the start and divide it up yourself - it's not like another user is going to want some.
You should always worry about performance and efficiency when your profiler tells you so (you can be that profiler, but you have to 'measure', not guess).
Things you can do:
pre-allocate capacity:
std::vector<int> x(1000); // size() is 1000
std::vector<int> y;
y.reserve(1000); // size() is 0, capacity is 1000
use a custom allocator
have a look at Boost Pool
have a look at EASTL (specialized for embedded/game programming)
STL Alternative
EASTL versus STL, how can there be such a performance difference in std::vector<uint64_t>::operator[]
The first option is clearly the quick win; The second option is more involved and I only recommend it when your heap profiler tells you that fragmentation is causing problems.
For heap profiling, I suggest
valgrind massif (see Using Massif and ms_print)
One good way to minimize repeated memory allocation and reallocation calls with std::vector is to make liberal use of std::vector::reserve() if you have some idea of how many elements your vector will be using. That will preallocate capacity and prevent the resizing of the internal array the vector is maintaining as you add elements via push_back().
No, std::vector guarantees contiguous storage. You can use vector::reserve() to avoid reallocations as the vector size increases though.

are STL Containers .push_back() naughty

This might seem daft for which I'm sorry, I've been writing a bit some code for the Playstation 2 for uni. I am writing a sort of API for the Graphic Synthesizer. I am using a similar syntax to that of openGL which is a state machine.
So the input would something like
gsBegin(GS_TRIANGLE);
gsColor(...);
gsVertex3f(...);
gsVertex3f(...);
gsVertex3f(...);
gsEnd();
This is great so far for line/triangles/quads with a determined amount of vertices, however things like a LINE_STRIP or TRIANGLE_FAN take an undetermined amount of points. I have been warned off several times for using stl containers because of the push_back() method in this situation because of the time sensitive nature (is this justified).
If its not justified what would be a better way of dealing with the undetermined amount situation. Currently I have an Array that can hold 30 vertices at a time, is this best way of dealing with this kind of situation?
Vector's push_back has amortized constant time complexity because it exponentially increases the capacity of the vector. (I'm assuming you're using vector, because it's ideal for this situation.) However, in practice, rendering code is very performance sensitive, so if the push_back causes a vector reallocation, performance may suffer.
You can prevent reallocations by reserving the capacity before you add to it. If you call myvec.reserve(10);, you are guaranteed to be able to add 10 elements before the vector reallocates.
However, this still requires knowing ahead of time how many elements you need. Also, if you create and destroy lots of different vectors, you're still doing a lot of memory allocation. Instead, just use one vector for all vertices, and re-use it. Calling clear() returns it to empty while keeping its allocated capacity. This way you don't actually need to reserve anything - the first few times you use it it'll reallocate and grow, but once it reaches its peak size, it won't need to reallocate any more. The nice thing about this is the vector finds the approximate size it needs to be, and once it's "warmed up" there's no further allocation so it is high performance.
In short:
Use a single persistently stored std::vector
push_back as much as you like
When you're done, clear().
In practice this will perform as well as a C array, but without a hard limit on size.
University, eh? Just tell them push_back has amortized constant time complexity and they'll be happy.
First, avoid using glBegin / glEnd if you can, and instead use something like glDrawArrays or glDrawElements.
push_back() on a std::vector is a quick operation unless the array needs to grow in size when the operation occurs. Set the vector capacity as high as you think you will need it to be and you should see minimal overhead. 'Raw' arrays will usually always be slightly faster, but then you have to deal with using 'raw' arrays.
There is always the alternative of using a deque.
A deque is very much like a vector, contiguity apart. Basically, it's often implemented as a vector of arrays.
This means a lower allocation cost, but member access might be slightly slower (though constant) because of the double dereference, so I am unsure if it's profitable in your case.
There is also the LLVM alternative: SmallVector<T,N>, which preallocates (right in the vector) space for N elements, and will simply get back to using a traditional vector-like implementation once the size has grown too much.
The drawback to using std::vector in this kind of situation is making sure you manage your memory allocation properly. On systems like the PS2 (PS3 seems to be a bit better at this), memory allocation is insanely slow and if you don't reserve the right amount of space in the vector to begin with (and it has to resize several times when adding items), you will slow your game to a creeping crawl. If you know what your max size is going to be and reserve it when you create the vector, you won't have a problem.
That said, if this vector is going to be a temporary/local variable, you will still be reallocating memory every time your function is called. So if this function is called every frame, you will still have the performance problem. You can get around this by using a custom allocator and/or making the vector global (or a member variable to a class that will exist during your game loop).
You can always equip the container you want to use with proper allocator, which takes into account the limitations of the platform and the expected grow/shrink scenarios etc...