I've got a problem with my terrain engine (using DirectX).
I'm using a vector to hold the vertices of a detail block.
When the block increases in detail, so the vector does.
BUT, when the block decreases its detail, the vector doesn't shrink in size.
So, my question: is there a way to shrink the size of a vector?
I did try this:
vertexvector.reserve(16);
If you pop elements from a vector, it does not free memory (because that would invalidate iterators into the container elements). You can copy the vector to a new vector, and then swap that with the original. That will then make it not waste space. The Swap has constant time complexity, because a swap must not invalidate iterators to elements of the vectors swapped: So it has to just exchange the internal buffer pointers.
vector<vertex>(a).swap(a);
It is known as the "Shrink-to-fit" idiom. Incidentally, the next C++ version includes a "shrink_to_fit()" member function for std::vector.
The usual trick is to swap with an empty vector:
vector<vertex>(vertexvector.begin(), vertexvector.end()).swap(vertexvector);
The reserved memory is not reduced when the vector size is reduced because it is generally better for performance. Shrinking the amount of memory reserved by the vector is as expensive as increasing the size of the vector beyond the reserved size, in that it requires:
Ask the allocator for a new, smaller memory location,
Copy the contents from the old location, and
Tell the allocator to free the old memory location.
In some cases, the allocator can resize an allocation in-place, but it's by no means guaranteed.
If you have had a very large change in the size required, and you know that you won't want that vector to expand again (the principal of locality suggests you will, but of course there are exceptions), then you can use litb's suggested swap operation to explicitly shrink your vector:
vector<vertex>(a).swap(a);
There is a member function for this, shrink_to_fit. Its more efficient than most other methods since it will only allocate new memory and copy if there is a need. The details are discussed here,
Is shrink_to_fit the proper way of reducing the capacity a `std::vector` to its size?
If you don't mind the libc allocation functions realloc is even more efficient, it wont copy the data on a shrink, just mark the extra memory as free, and if you grow the memory and there is memory free after it will mark the needed memory as used and not copy either. Be careful though, you are moving out of C++ stl templates into C void pointers and need to understand how pointers and memory management works, its frowned upon by many now adays as a source for bugs and memory leaks.
Related
What is the safe, portable, idiomatic way to use the spare capacity in a std::vector?
std::vector<Foo> foos;
foos.emplace_back(1);
foos.emplace_back(2);
foos.reserve(10);
At this point, foos owns at least 8 * sizeof(Foo) uninitialized spare memory starting at foos.data() + foos.size(). It seems terribly inefficient to let that memory go to waste. How can I use this spare capacity as scratch space or for other purposes before I fill it with Foo objects by appending to foos? What is the right way to do this without invoking any undefined behavior?
How can I use the spare capacity in a std::vector?
By inserting more elements.
More convoluted answer which may be what you're looking for, but probably more complex than it's worth:
You can allocate memory yourself (std::allocator or whatever; don't forget std::unique_ptr), and implement a custom allocator that uses that piece of memory. You can then use that memory for whatever and later create a vector using the custom allocator. Note that this doesn't let you use the memory that has already been reserved for the vecor; you can only use the memory before it has been acquired by the vector.
Yes, memory for unused elements is wasted, but it is unavoidable. It's by design.
The storage of the vector is handled automatically, being expanded and
contracted as needed. Vectors usually occupy more space than static
arrays, because more memory is allocated to handle future growth. This
way a vector does not need to reallocate each time an element is
inserted, but only when the additional memory is exhausted.
It's also good to know some non-standard vector's variants and may use them as replacement for std::vector, they
have specific application scenarios.
If you need a dynamic array and the maximum capacity is know at compile timeļ¼then boost::static_vector would be a choice(Use it may avoid the unnecessary memory waste of std::vector since most of std::vector's implementation always reserve capacity with a pow of 2, so if your desired capacity is 10, then 6 elements is likely to
be waste):
static_vector is an hybrid between vector and array: like vector, it's
a sequence container with contiguous storage that can change in size,
along with the static allocation, low overhead, and fixed capacity of
array. static_vector is based on Adam Wulkiewicz and Andrew Hundt's
high-performance varray class.
The number of elements in a static_vector may vary dynamically up to a
fixed capacity because elements are stored within the object itself
similarly to an array. However, objects are initialized as they are
inserted into static_vector unlike C arrays or std::array which must
construct all elements on instantiation. The behavior of static_vector
enables the use of statically allocated elements in cases with complex
object lifetime requirements that would otherwise not be trivially
possible. Some other properties:
Random access to elements Constant time insertion and removal of
elements at the end Linear time insertion and removal of elements at
the beginning or in the middle. static_vector is well suited for use
in a buffer, the internal implementation of other classes, or use
cases where there is a fixed limit to the number of elements that must
be stored. Embedded and realtime applications where allocation either
may not be available or acceptable are a particular case where
static_vector can be beneficial.
And if the dynamic array mostly has a very small size(only some of them would be large but with a small probability), then we may consider using small_vector, a small vector will improve the performance for such a scenario and such container is widely used in large projects.
small_vector is a vector-like container optimized for the case when it
contains few elements. It contains some preallocated elements
in-place, which allows it to avoid the use of dynamic storage
allocation when the actual number of elements is below that
preallocated threshold. small_vector is inspired by LLVM's SmallVector
container. Unlike static_vector, small_vector's capacity can grow
beyond the initial preallocated capacity.
The standard STL vector container has a "reserve" function to reserve uninitialized memory that can be used later to prevent reallocations.
How come that the other deque container hasn't it?
Increasing the size of a std::vector can be costly. When a vector outgrows its reserved space, the entire contents of the vector must be copied (or moved) to a larger reserve.
It is specifically because std::vector resizing can be costly that vector::reserve() exists. reserve() can prepare a std::vector to anticipate reaching a certain size without exceeding its capacity.
Conversely, a deque can always add more memory without needing to relocate the existing elements. If a std::deque could reserve() memory, there would be little to no noticeable benefit.
For vector and string, reserved space prevents later insertions at the end (up to the capacity) from invalidating iterators and references to earlier elements, by ensuring that elements don't need to be copied/moved. This relocation may also be costly.
With deque and list, earlier references are never invalidated by insertions at the end, and elements aren't moved, so the need to reserve capacity does not arise.
You might think that with vector and string, reserving space also guarantees that later insertions will not throw an exception (unless a constructor throws), since there's no need to allocate memory. You might think that the same guarantee would be useful for other sequences, and hence deque::reserve would have a possible use. There is in fact no such guarantee for vector and string, although in most (all?) implementations it's true. So this is not the intended purpose of reserve.
Quoting from C++ Reference
As opposed to std::vector, the elements of a deque are not stored contiguously: typical implementations use a sequence of individually allocated fixed-size arrays.
The storage of a deque is automatically expanded and contracted as needed. Expansion of a deque is cheaper than the expansion of a std::vector because it does not involve copying of the existing elements to a new memory location.
Deque can allocate new memory anywhere it wants and just point to it, unlike vectors which require a continuous block of memory to hold all their elements.
Only vector have. There is no need of reserve function for deque, since elements not stored continuougusly and there is no need to reallocate and move elements when add, or remove elements.
reserve implies allocation of large blocks of contiguous data (like a vector). There is nothing in the dequeue that implies contiguous storage - it's generally implemented more like a list (which you will notice also doesn't have a 'reserve' function).
Thus, a 'reserve' function would make no sense.
There are 2 main types of memory: memories that allocate a single chunk like array and vectors, and distributed memories whose members grabs any empty location to fill in. queue and linkest list structures belong to the second type and they have some special practical advantages such that deleting a particular element does not cause a mass memory movement as opposed to arrays and vectors. Therefore they do not need to reserve any space beforehand, if they need it they just take it by connecting to tip
If you aim for having aligned memory containers you could think about implementing something like this:
std::deque<std::vector> dv; //deque with dynamic size memory aligned vectors.
typedef size_t[N] Mem;
std::deque<Mem> dvf //deque with fixed size memory aligned vectors. Here you can store the raw bytes adding a header to loop through and cast using header information and typeid...
//templates and polymorphism can help storing raw bytes, checking the type where a pointer points for example, and creating an interface to access the partial aligned memory.
Alternatively you can use a map to access the vectors instead of a deque...
Is there any known header-only STL-like container/allocator for appending chunks of memory to another continuos memory area until it's filled? At the moment I am using a std::vector<char> vec, because it has some useful interface, but it's not optimal and somehow I think I am abusing it for my needs.
I first use std::vector::reserve to fix its capacity and allocate the required memory once for all to avoid unnecessary reallocations and then use std::copy(&chunk[0], &chunk[size], vec.data() + vec.size()) each time to append the new chunks of memory to the unfilled memory area behind the vector (of course size() <= capacity()). After each copy I explicitly update the size of the vector accordingly. Ok, I could use a back_inserter. But this not the point now (see below).
Of course std::copy could be specialized for char by any implementation so that it can just call memcpy at the end, but this is not a guarantee. Calling memcpy by myself to append the chunk to the memory already allocated by the vector to have such guarantee is just ugly. Are there better/more elegant options?
EDIT: I have no control on how the chunks of memory are allocated. They are given.
Basically the only way to "really" append memory to a contiguous memory area is to use the Posix function realloc(). Even with these allocated regions you can use std::copy, you only have to maintain knowledge about the end position in your region.
However, realloc() does not guarantee that the memory area will be at the previous memory location, but rather that the new block is fully contiguous. See man page for more details.
Few things to remember:
If you allocated memory via posix_memalign() it is not guaranteed that the memory alignment will be kept
There is no way to find out if the realloc() copied the data or not.
I know it's not exactly what you want, but std::deque usually stitches together contiguous blocks of memory.
There aren't any re-allocations as it grows, but the whole data may not be contiguous.
edit
Using a vector with preallocated memory, you can insert values at the end, which won't result in a reallocation unless the new values would make the size exceed the capacity:
vector<char> values(PRE_ALLOCATED_SIZE);
// ...
values.insert(values.end(), chunk, chunk+CHUNK_SIZE);
This probably is not what you're looking for, since they are designed for homogenous containers (i.e. where all the elements have the same type). I don't know if that fits your use case. On the off chance that you find it useful, I point you at:
get_temporary_buffer -- allocate raw storage (there's also a way to return the storage).
raw_storage_iterator -- output iterator over raw storage.
uninitialized_copy_n -- Copy construct several objects into raw storage (there is also a single element version).
I know that vectors double in size whenever their capacity() is exceeded. This operation takes some time which is why vectors are supposed to have amortized constant time for addition of elements with push_back().
What I'm wondering is... what happens when a vector shrinks so that its size() is less than half of the capacity().
Do vectors ever relinquish the memory which they use, or is it just gone until the vector is destroyed?
It could be a lot of wasted memory if they don't shrink in size ever, but I've never heard of them having that feature.
No, it is never freed (i.e. capacity is never reduced) until destruction. A common idiom for freeing up some memory is to create a new vector of the correct size, and use that instead:
std::vector<type>(originalVector).swap(originalVector);
(inspired by "More Exceptional C++", Item #7)
If you want to make sure your vector uses as little space as possible, you can say:
std::vector<Foo>(my_vector).swap(my_vector);
You could also call the shrink_to_fit() member function, but that is just a non-binding request.
Erasing elements from a vector or even clearing the vector entirely does not necessarily free any of the memory associated with that element. This is because the maximum size of a vector since its creation is a good estimate of the future size of the vector.
To use the shrink to fit idiom:
std::vector<int> v;
//v is swapped with its temporary copy, which is capacity optimal
std::vector<int>(v).swap(v);
Solution in C++0x
In C++0x some containers declare such idiom as function shrink_to_fit(), e.g. vector, deque, basic_string. shrink_to_fit() is a non-binding request to reduce capacity() to size().
They don't shrink in size.
It would not be generally useful to de-allocate the memory.
For example, a vector could shrink now but then grow again later. It would be a waste to deallocate the extra memory (and copy all the elements in the memory) only to reallocate it later.
If a vector is shrinking, there is also a good chance the vector will be shrunk to empty and then destroyed. In that case deallocating as it shrinks would be a waste of time as well.
It can also be a useful optimization to reuse a vector object so as to avoid allocating/dealocating the contents. That would be ruined by introducing deallocations as it shrinks.
Basically, most of the time deallocating the extra memory isn't worth it. In the few case where it is, you can specifically ask for dealocation.
The memory is gone until the vector is destroyed.
Memory usage in my STL containers is projected to be volatile - that is to say it will frequently shrink and grow. I'm thinking to account for this by specifying an allocator to the STL container type declarations. I understand that pool allocators are meant to handle this type of situation, but my concern is that the volatility will be more than the pool accounts for, and to overcome it I would have to do a lot of testing to determine good pool metrics.
My ideal allocator would never implicitly release memory, and in fact is perfectly acceptable if memory is only ever released upon destruction of the allocator. A member function to explicitly release unused memory would be nice, but not necessary. I know that what I'm referring to sounds like a per-object allocator and this violates the standard. I'd rather stick with the standard, but will abandon it if I can't resolve this within it.
I am less concerned with initial performance and more with average performance. Put another way, it matters less whether a single element or a pool of them is allocated at a time, and more whether said allocation results in a call to new/malloc. I have no problem writing my own allocator, but does anyone know of a preexisting one that accomplishes this? If it makes a difference, this will be for contiguous memory containers (e.g. vector, deque), although a generalized solution would be nice.
I hope this isn't too basic.
Memory will be allocated and freed more for adding items than removing them.
I believe that never "freeing" memory isn't possible unless you know the maximum number of elements allowed by your application. The CRT might try to allocate a larger block of memory in place, but how would you handle the failure cases?
Explaination:
To create a dynamically expanding vector, there will be a larger capacity to handle most push_backs, and a reallocation to handle when this is insufficient.
During the reallocation, a new larger piece of memory is "newed" up
and the elements of the old piece of memory are copied into the new
one.
It is important that you don't hold any iterators while to push_back
elements, because the reallocation will invalidate the memory
locations the iterator point to.
In c++11 and TR1, you might have perfect forwarding where only the
pointer to the elements need to be copied. This is done via a move
constructor instead of a copy constructor.
However, you seem to want to avoid reallocation as much as possible.
Using the default allocator for vector you can specify an initial capacity.
Capacity is the memory allocated and size is the number of elements.
Memory will only be allocated at construction and if the size reaches
capacity. This should only happen with a push_back();
The default allocator will increase the capacity by a multiple (eg.
1.5, 2.0) so that reallocation takes place in linear time. So if you have a loop that pushes back data it's linear. Or if you know the number of elements ahead of time you can allocate once.
There are pool concepts you can explore. The idea with a pool is you are not destroying elements but deactivating them.
If you still want to write your own allocator, this is a good article.
custom allocators