什么时候应该使用矢量的reserve()?

时间:2012-01-05 13:24:50

标签: vector stdvector

我总是使用resize(),因为我不能使用reserve,因为它给出了错误:向量下标超出范围。当我读到有关resize()和reserve()的差异的信息时,我看到像reserve()这样的东西设置了最大值。可以分配元素的数量,但resize()是我们现在拥有的。在我的代码中我知道max。元素的数量,但reserve()并没有给我任何有用的东西。那么,我怎样才能使用reserve()?

4 个答案:

答案 0 :(得分:9)

向量具有容量(由capacity()返回, size (由size()返回。)第一个说明有多少元素一个矢量可以持有,第二个目前持有的数量。

resize更改尺寸,reserve仅更改capacity

另请参阅resizereserve文档。

用例: 假设您事先知道要将多少元素添加到vector中,但是您不想初始化它们 - 这就是保留的用例。假设你的矢量之前是空的;然后,直接在reserve()之后,在执行任何insertpush_back之前,您当然可以不直接访问与保留空间一样多的元素 - 这将触发上述错误(下标超出范围) - 因为您尝试访问的元素尚未初始化; size仍为0.因此向量仍为空;但如果您选择保留容量的方式使其高于或等于矢量将获得的最大大小,则可以避免昂贵的重新分配;同时你也会避免调整大小的每个向量元素的初始化(在某些情况下是昂贵的)。

另一方面,对于resize,你说:让向量保持尽可能多的元素作为参数;初始化索引超过旧大小的那些,或删除超过给定新大小的那些。

请注意,reserve 永远不会影响当前在向量中的元素(如果需要重新分配,则除了存储位置 - 但不会影响其值或数量)!这意味着如果向量的大小当前大于传递给同一向量上的保留函数的调用,则保留将不执行任何操作。

另请参阅此问题的答案:Choice between vector::resize() and vector::reserve()

答案 1 :(得分:3)

reserve()是使用std :: vector的性能优化

典型的std :: vector实现会在第一个push_back()上保留一些内存,例如4个元素。当推送第5个元素时,必须调整向量的大小:必须分配新内存(通常大小加倍),向量的内容必须复制到新位置,并且必须删除旧内存

当向量包含大量元素时,这将成为一项昂贵的操作。例如,当你push_back()2 ^ 24 + 1个元素时,16Million元素被复制只是为了添加一个元素。

如果您事先知道元素数量,则可以reserve()计划push_back()元素的数量。在这种情况下,不需要昂贵的复制操作,因为已经为所需的数量保留了内存。

调整大小(),而会更改向量中的元素数量

如果没有添加任何元素并使用resize(20),则现在可以访问20个元素。此外,分配的内存量将增加到与实现相关的值。 如果添加了50个元素并使用resize(20),则最后30个元素将从向量中删除,不再可访问。这不一定会改变分配的内存,但这也可能与实现有关。

答案 2 :(得分:2)

resize(n)为n个对象分配内存并默认初始化它们。

reserve()分配内存但不初始化。因此,reserve不会更改size()返回的值,但会更改capacity()的结果。

答案 3 :(得分:-1)

在undercore_d评论后编辑。

描述VS2015中实现的功能

VS2015 CTP6

当定义#if _ITERATOR_DEBUG_LEVEL == 2时,此错误对话框仅存在于DEBUG模式中。在RELEASE模式下,我们没有任何问题。我们得到return (*(this->_Myfirst() + _Pos)的当前值,因此不需要size值:

    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));
    }

如果我们在向量的源代码中看到,我们可以发现,resizereserve之间的差异仅在于更改this->_Mylast()的值功能resize()

reserve()来电_Reallocate

resize()调用_Reserve,调用_Reallocate然后resize()也会更改this->_Mylast()this->_Mylast() += _Newsize - size();的值size计算(见最后一个函数)

    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());
    }

问题

reserve存在一些问题:

  1. end()将等于begin()
  2. 23.2.1一般容器要求

    <强> 5

    end()返回一个迭代器,它是容器的过去值。

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

    即。 _Mylast()将等于_Myfirst()

    1. at()将生成out_of_range异常。
    2. 23.2.3序列容器

      <强> 17

      ()处的成员函数提供对容器元素的边界检查访问。如果n&gt; = a.size(),at()会抛出out_of_range。

      1. 在VisualStudio调试器中,我们可以看到矢量值,当大小不是&n;&lt; t 0
      2. resize

        enter image description here

        使用reserve并手动设置#define _ITERATOR_DEBUG_LEVEL 0

        enter image description here

相关问题