Difference between revisions of "cpp/container/vector/reserve"
m (→Example: made the allocator even more verbose: it prints now (size == capacity) events, and alloc/dealloc addresses.) |
|||
Line 32: | Line 32: | ||
If an exception is thrown, this function has no effect ([[cpp/language/exceptions|strong exception guarantee]]). | If an exception is thrown, this function has no effect ([[cpp/language/exceptions|strong exception guarantee]]). | ||
{{rrev | since=c++11 | | {{rrev | since=c++11 | | ||
− | If {{tt|T}}'s move constructor is not {{c|noexcept}} and T is not {{named req|CopyInsertable}} into {{ | + | If {{tt|T}}'s move constructor is not {{c|noexcept}} and T is not {{named req|CopyInsertable}} into {{c|*this}}, vector will use the throwing move constructor. If it throws, the guarantee is waived and the effects are unspecified. |
}} | }} | ||
Line 49: | Line 49: | ||
|code= | |code= | ||
#include <cstddef> | #include <cstddef> | ||
+ | #include <iostream> | ||
#include <new> | #include <new> | ||
#include <vector> | #include <vector> | ||
− | |||
// minimal C++11 allocator with debug output | // minimal C++11 allocator with debug output | ||
Line 63: | Line 63: | ||
{ | { | ||
n *= sizeof(Tp); | n *= sizeof(Tp); | ||
− | std::cout << "allocating " << n << " bytes\n | + | Tp* p = static_cast<Tp*>(::operator new(n)); |
− | return | + | std::cout << "allocating " << n << " bytes @ " << p << '\n'; |
+ | return p; | ||
} | } | ||
− | void deallocate(Tp* p, std::size_t n) | + | void deallocate(Tp* p, std::size_t n) |
{ | { | ||
− | std::cout << "deallocating " << n*sizeof*p << " bytes\n"; | + | std::cout << "deallocating " << n*sizeof*p << " bytes @ " << p << "\n\n"; |
::operator delete(p); | ::operator delete(p); | ||
} | } | ||
Line 80: | Line 81: | ||
int main() | int main() | ||
{ | { | ||
− | int | + | constexpr int max_elements = 32; |
+ | |||
std::cout << "using reserve: \n"; | std::cout << "using reserve: \n"; | ||
{ | { | ||
std::vector<int, NAlloc<int>> v1; | std::vector<int, NAlloc<int>> v1; | ||
− | v1.reserve( | + | v1.reserve( max_elements ); // reserves at least max_elements * sizeof(int) bytes |
− | for(int n = 0; n < | + | |
+ | for(int n = 0; n < max_elements; ++n) | ||
v1.push_back(n); | v1.push_back(n); | ||
} | } | ||
+ | |||
std::cout << "not using reserve: \n"; | std::cout << "not using reserve: \n"; | ||
{ | { | ||
std::vector<int, NAlloc<int>> v1; | std::vector<int, NAlloc<int>> v1; | ||
− | for(int n = 0; n < | + | |
+ | for(int n = 0; n < max_elements; ++n) { | ||
+ | if(v1.size() == v1.capacity()) { | ||
+ | std::cout << "size() == capacity() == " << v1.size() << '\n'; | ||
+ | } | ||
v1.push_back(n); | v1.push_back(n); | ||
+ | } | ||
} | } | ||
} | } | ||
− | |p=true | + | | p=true |
− | |output= | + | | output= |
using reserve: | using reserve: | ||
− | allocating | + | allocating 128 bytes @ 0xa6f840 |
− | deallocating | + | deallocating 128 bytes @ 0xa6f840 |
+ | |||
not using reserve: | not using reserve: | ||
− | allocating 4 bytes | + | size() == capacity() == 0 |
− | allocating 8 bytes | + | allocating 4 bytes @ 0xa6f840 |
− | deallocating 4 bytes | + | |
− | allocating 16 bytes | + | size() == capacity() == 1 |
− | deallocating 8 bytes | + | allocating 8 bytes @ 0xa6f860 |
− | allocating 32 bytes | + | deallocating 4 bytes @ 0xa6f840 |
− | deallocating 16 bytes | + | |
− | allocating 64 bytes | + | size() == capacity() == 2 |
− | deallocating 32 bytes | + | allocating 16 bytes @ 0xa6f840 |
− | allocating 128 bytes | + | deallocating 8 bytes @ 0xa6f860 |
− | deallocating 64 bytes | + | |
− | + | size() == capacity() == 4 | |
− | deallocating 128 bytes | + | allocating 32 bytes @ 0xa6f880 |
− | + | deallocating 16 bytes @ 0xa6f840 | |
− | + | ||
− | + | size() == capacity() == 8 | |
+ | allocating 64 bytes @ 0xa6f8b0 | ||
+ | deallocating 32 bytes @ 0xa6f880 | ||
+ | |||
+ | size() == capacity() == 16 | ||
+ | allocating 128 bytes @ 0xa6f900 | ||
+ | deallocating 64 bytes @ 0xa6f8b0 | ||
+ | |||
+ | deallocating 128 bytes @ 0xa6f900 | ||
}} | }} | ||
Revision as of 06:11, 22 September 2021
void reserve( size_type new_cap ); |
(until C++20) | |
constexpr void reserve( size_type new_cap ); |
(since C++20) | |
Increase the capacity of the vector to a value that's greater or equal to new_cap
. If new_cap
is greater than the current capacity(), new storage is allocated, otherwise the function does nothing.
reserve()
does not change the size of the vector.
If new_cap is greater than capacity(), all iterators (including the end()
iterator) and all references to the elements are invalidated. Otherwise, no iterators or references are invalidated.
Contents |
Parameters
new_cap | - | new capacity of the vector |
Type requirements | ||
-T must meet the requirements of MoveInsertable.
|
Return value
(none)
Exceptions
- std::length_error if new_cap > max_size().
- any exception thrown by
Allocator::allocate()
(typically std::bad_alloc)
If an exception is thrown, this function has no effect (strong exception guarantee).
If |
(since C++11) |
Complexity
At most linear in the size() of the container.
Notes
Correctly using reserve()
can prevent unnecessary reallocations, but inappropriate uses of reserve()
(for instance, calling it before every push_back() call) may actually increase the number of reallocations (by causing the capacity to grow linearly rather than exponentially) and result in increased computational complexity and decreased performance. For example, a function that receives an arbitrary vector by reference and appends elements to it should usually not call reserve()
on the vector, since it does not know of the vector's usage characteristics.
When inserting a range, the range version of insert() is generally preferable as it preserves the correct capacity growth behavior, unlike reserve()
followed by a series of push_back()s.
reserve()
cannot be used to reduce the capacity of the container; to that end shrink_to_fit() is provided.
Example
#include <cstddef> #include <iostream> #include <new> #include <vector> // minimal C++11 allocator with debug output template <class Tp> struct NAlloc { typedef Tp value_type; NAlloc() = default; template <class T> NAlloc(const NAlloc<T>&) {} Tp* allocate(std::size_t n) { n *= sizeof(Tp); Tp* p = static_cast<Tp*>(::operator new(n)); std::cout << "allocating " << n << " bytes @ " << p << '\n'; return p; } void deallocate(Tp* p, std::size_t n) { std::cout << "deallocating " << n*sizeof*p << " bytes @ " << p << "\n\n"; ::operator delete(p); } }; template <class T, class U> bool operator==(const NAlloc<T>&, const NAlloc<U>&) { return true; } template <class T, class U> bool operator!=(const NAlloc<T>&, const NAlloc<U>&) { return false; } int main() { constexpr int max_elements = 32; std::cout << "using reserve: \n"; { std::vector<int, NAlloc<int>> v1; v1.reserve( max_elements ); // reserves at least max_elements * sizeof(int) bytes for(int n = 0; n < max_elements; ++n) v1.push_back(n); } std::cout << "not using reserve: \n"; { std::vector<int, NAlloc<int>> v1; for(int n = 0; n < max_elements; ++n) { if(v1.size() == v1.capacity()) { std::cout << "size() == capacity() == " << v1.size() << '\n'; } v1.push_back(n); } } }
Possible output:
using reserve: allocating 128 bytes @ 0xa6f840 deallocating 128 bytes @ 0xa6f840 not using reserve: size() == capacity() == 0 allocating 4 bytes @ 0xa6f840 size() == capacity() == 1 allocating 8 bytes @ 0xa6f860 deallocating 4 bytes @ 0xa6f840 size() == capacity() == 2 allocating 16 bytes @ 0xa6f840 deallocating 8 bytes @ 0xa6f860 size() == capacity() == 4 allocating 32 bytes @ 0xa6f880 deallocating 16 bytes @ 0xa6f840 size() == capacity() == 8 allocating 64 bytes @ 0xa6f8b0 deallocating 32 bytes @ 0xa6f880 size() == capacity() == 16 allocating 128 bytes @ 0xa6f900 deallocating 64 bytes @ 0xa6f8b0 deallocating 128 bytes @ 0xa6f900
See also
returns the number of elements that can be held in currently allocated storage (public member function) | |
returns the maximum possible number of elements (public member function) | |
changes the number of elements stored (public member function) | |
(DR*) |
reduces memory usage by freeing unused memory (public member function) |