Given a std::vector
, whose size and capacity can be arbitrary, what's the best practice to change its size to 0 and capacity to at least N(a given number)?
My direct idea is:
void f(vector<int> &t, int N)
{
t.clear();
t.reserve(N);
}
but I noticed that
A reallocation is not guaranteed to happen, and the vector capacity is not guaranteed to change(when std::vector::clear is called).
So I'm wondering how to avoid reallocating when the origin capacity is larger than the given N?
what's the best practice to change its size to 0 and capacity to N(a given number)? My direct idea is: ...
Your direct idea is correct, and the simplest option. Although to be pedantic, reserve
changes capacity to greater or equal to the given number; not guaranteed to be equal (but all implementations I've tested do allocate exactly the given amount if the previous capacity was less).
So I'm wondering how to avoid reallocating when the origin capacity is larger than the given N?
By using a standard library implementation that has chosen to not deallocate the memory on a call to clear
(i.e. any standard conforming implementation, as indicated by the answer here).
Another approach to guarantee (although, it appears that this is not necessary as the above should be guaranteed, despite the weak wording on cplusplus.com) no reallocation (in the case N > t.capacity()
): Since the vector contains simple integers, and you appear to know how many elements there will be (as you know to reserve), you could simply call t.resize(N)
(to remove extra elements in case size was greater) without clearing the vector, and then proceed to overwrite the existing elements, rather than push new ones.
Of course, this means that you won't be able to observe the number of elements that have been overwritten, so this approach is not applicable for all use cases. It's fine if you simply want to fill the vector with a simple loop.
You might possibly want to reserve before resizing if the new size might be greater than the old, and you desire to not over-allocate. This is because most implementations allocate exact amount on reserve (as I mentioned) but use multiplication strategy on resize (neither of these behaviours are guaranteed as far as I know, but the implementations I've used have been consistent with this behaviour).
The best way is probably your current code.
Unfortunately, the standard allows an implementation to have containers whose capacity can only grow. In that case, your code will only guarantee that capacity is at least N. A reallocation will occur if initial capacity is less that N, and nothing will happen if capacity is greater that N. This points are guaranteed by the standard because draft 4659 for C++17 says at [vector.capacity] (emphasize mine):
void reserve(size_type n);
...
3 Effects: A directive that informs a vector of a planned change in size, so that it can manage the storage allocation accordingly. After reserve(), capacity() is greater or equal to the argument of reserve if reallocation happens; and equal to the previous value of capacity() otherwise. Reallocation happens at this point if and only if the current capacity is less than the argument of reserve().
and
void shrink_to_fit();
...
8 Effects: shrink_to_fit is a non-binding request to reduce capacity() to size(). [ Note: The request is non-binding to allow latitude for implementation-specific optimizations. —end note ] It does not increase capacity(), but may reduce capacity() by causing reallocation.
You have no way to guarantee that the capacity will be exactly N. Instead your code guarantees that if the initial capacity is greater than N in will be unchanged and no reallocation will happen.
Edit: this behaviour is stable at least since C++11 (draft n3337)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With