When should we use reserve () vectors?

I always use resize () because I cannot use the reserve because it gives an error: the vector index is out of range. When I read information about the differences in resize () and reserve (), I saw things like reserve () sets max. the number of elements can be allocated, but resize () is what we have. In my code, I know max. number of elements, but reserve () does not give me anything useful. So how can I use reserve ()?

+4
source share
4 answers

A vector has a capacity (returned by capacity() and size (as returned by size() ). First, how many elements the vector has The second is how much it is currently running .

resize resizes; reserve only resizes.

See also resize and reserve .

As for the use cases: Let's say you know in advance how many elements you want to put in your vector , but you do not want to initialize them - this is a use case for the reserve. Let them say that your vector was empty before; then, immediately after reserve() , before performing any insert or push_back , you may, of course, not have direct access to the number of elements for which you reserved space - which will cause the indicated error (index out of range) - since the elements The ones you are trying to get are not yet initialized; size is still 0. So the vector is still empty; but if you choose a reserved capacity so that it is higher or equal to the maximum size of your vector, you avoid costly redistributions; and at the same time, you will also avoid (in some cases costly) initializing every vector element that will resize.

With resize , on the other hand, you say: make the vector hold as many elements as I gave as an argument; initialize those whose indexes exceed the old size, or delete those that exceed this new size.

Please note that reserve will never affect the elements that are currently in the vector (except for the storage location if redistribution is required, but not their values ​​or their number)! This means that if the size of the vector is currently larger than the one you pass to the call to the fallback function on the same vector, the fallback will do nothing.

See also the answer to this question: Choosing between vector :: resize () and vector :: reserve ()

+9
source

resize (n) allocates memory for n objects and initializes them by default.

reserve () allocates memory but does not initialize. Therefore, the reserve will not change the value returned by size (), but it will change the result of capacity ().

+2
source

reserve () is a performance optimization for using std :: vector.

A typical std :: vector implementation would reserve some memory on the first push_back (), for example 4 elements. When the fifth element is pressed, the vector must be changed: a new memory must be allocated (usually the size is doubled), the contents of the vector must be copied to a new location, and the old memory must be deleted.

This becomes an expensive operation when a vector contains many elements. For example, when you push_back () 2 ^ 24 + the 1st element, 16 million elements are copied only to add one element.

If you know the number of elements in advance, you can reserve() number of elements you plan push_back() . In this case, expensive copy operations are not needed, since the memory is already reserved for the required amount.

resize () , unlike resizes the number of elements in a vector.

If no elements are added and you use resize(20) , 20 elements will now be available. Also, the amount of allocated memory will increase to a value that depends on the implementation. If 50 elements are added and you use resize(20) , the last 30 elements will be removed from the vector and will no longer be available. This does not necessarily change the allocated memory, but it may also be implementation dependent.

+2
source

Edited after comment underscore_d.

Description of functions implemented in VS2015

VS2015 CTP6

This error dialog box only exists in DEBUG mode when #if _ITERATOR_DEBUG_LEVEL == 2 defined. In RELEASE mode, we have no problems. We get the current value of return (*(this->_Myfirst() + _Pos) , so the size value is not required:

  reference operator[](size_type _Pos) { // subscript mutable sequence #if _ITERATOR_DEBUG_LEVEL == 2 if (size() <= _Pos) { // report error _DEBUG_ERROR("vector subscript out of range"); _SCL_SECURE_OUT_OF_RANGE; } #elif _ITERATOR_DEBUG_LEVEL == 1 _SCL_SECURE_VALIDATE_RANGE(_Pos < size()); #endif /* _ITERATOR_DEBUG_LEVEL */ return (*(this->_Myfirst() + _Pos)); } 

If we see the vector in the source code, we can find that the difference between resize and reserve is only in changing the value of this->_Mylast() to func resize() .

reserve() calls _Reallocate .

resize() calls _Reserve , which calls _Reallocate , and then resize() also changes the value of this->_Mylast() : this->_Mylast() += _Newsize - size(); used in calculating size (see last function)

  void resize(size_type _Newsize) { // determine new length, padding as needed if (_Newsize < size()) _Pop_back_n(size() - _Newsize); else if (size() < _Newsize) { // pad as needed _Reserve(_Newsize - size()); _TRY_BEGIN _Uninitialized_default_fill_n(this->_Mylast(), _Newsize - size(), this->_Getal()); _CATCH_ALL _Tidy(); _RERAISE; _CATCH_END this->_Mylast() += _Newsize - size(); } } void reserve(size_type _Count) { // determine new minimum length of allocated storage if (capacity() < _Count) { // something to do, check and reallocate if (max_size() < _Count) _Xlen(); _Reallocate(_Count); } } void _Reallocate(size_type _Count) { // move to array of exactly _Count elements pointer _Ptr = this->_Getal().allocate(_Count); _TRY_BEGIN _Umove(this->_Myfirst(), this->_Mylast(), _Ptr); _CATCH_ALL this->_Getal().deallocate(_Ptr, _Count); _RERAISE; _CATCH_END size_type _Size = size(); if (this->_Myfirst() != pointer()) { // destroy and deallocate old array _Destroy(this->_Myfirst(), this->_Mylast()); this->_Getal().deallocate(this->_Myfirst(), this->_Myend() - this->_Myfirst()); } this->_Orphan_all(); this->_Myend() = _Ptr + _Count; this->_Mylast() = _Ptr + _Size; this->_Myfirst() = _Ptr; } void _Reserve(size_type _Count) { // ensure room for _Count new elements, grow exponentially if (_Unused_capacity() < _Count) { // need more room, try to get it if (max_size() - size() < _Count) _Xlen(); _Reallocate(_Grow_to(size() + _Count)); } } size_type size() const _NOEXCEPT { // return length of sequence return (this->_Mylast() - this->_Myfirst()); } 

Problems

But there are some problems with reserve :

  • end() will be equal to begin()

23.2.1 General requirements for containers

5:

end() returns an iterator, which is the final value for the container.

  iterator end() _NOEXCEPT { // return iterator for end of mutable sequence return (iterator(this->_Mylast(), &this->_Get_data())); } 

i.e. _Mylast() will be equal to _Myfirst()

  1. at () throws an out_of_range exception.

23.2.3 Sequence Containers

17:

The member function in () provides limited access to the elements of the container. at () returns out_of_range if n> = a.size ().

  1. in the VisualStudio debugger we can see vector values ​​when the size is not 0

with resize :

enter image description here

with reserve and manually set #define _ITERATOR_DEBUG_LEVEL 0 :

enter image description here

-1
source

Source: https://habr.com/ru/post/1389468/


All Articles