When should we use reserve() of vector?

后端 未结 4 2004
甜味超标
甜味超标 2021-01-06 03:47

I always use resize() because I cannot use reserve as it gives error: vector subscript out of range. As I\'ve read info about the differences of resize() and reserve(), I sa

4条回答
  •  太阳男子
    2021-01-06 04:32

    Edited after underscore_d's comment.

    Description how functions implemented in VS2015

    VS2015 CTP6

    This error dialog exist only in the DEBUG mode, when #if _ITERATOR_DEBUG_LEVEL == 2 is defined. In the RELEASE mode we don't have any problems. We get a current value by return (*(this->_Myfirst() + _Pos), so size value isn't needed:

        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 in the vector's source code, we can find, that a difference between resize and reserve is only in the changing of the value of this->_Mylast() in the func resize().

    reserve() calls _Reallocate.

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

        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 some problems exist with reserve:

    1. end() will be equal to begin()

    23.2.1 General container requirements

    5:

    end() returns an iterator which is the past-the-end 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 _Myfirst()

    1. at() will generate an out_of_range exception.

    23.2.3 Sequence containers

    17:

    The member function at() provides bounds-checked access to container elements. at() throws out_of_range if n >= a.size().

    1. in the VisualStudio debugger we can see vector values, when size isn't 0

    with resize:

    enter image description here

    with reserve and manually setted #define _ITERATOR_DEBUG_LEVEL 0:

    enter image description here

提交回复
热议问题