欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

vector的resize和reserve的小研究

程序员文章站 2022-03-21 21:22:14
...

问题描述

今天遇到一个问题,有同事使用vector的reserve并且直接取第一个元数来用,伪代码如下:

m_arrsAP.reserve(uCount);
AP* pAP = &m_arrsAP[0];

结果报错如下:

vector subscript out of range

当时想到的是size和capacity的区别,所以把代码改成resize,的确也就ok了。但是,也产生了如下一些问题:
疑问如下:

  1. 为什么在release下面没有,而在debug下面报错?
  2. size和capacity区别的意义是什么?
  3. resize和reserve区别的意义又是什么?
  4. reserve会改变空间大小,那么地址会变,得去验证一下。

release和debug的区别

看一下代码就很容易知道了,Debug下面Level为2的时候才有,如果设置了vs的Level也可能会不报错。

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

size和capacity

这两个区别大家一般都知道,size是当前vector里面的元数个数,capacity是当前vector最多可容纳的元数个数,size <= capacity

resize和reserve

size和capacity区别了解了之后,resize和reserve就自然是改变这两个值相关操作的。但是这两个函数的实现最终还是有很多看点的,往下看:

resize

源码:

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

说明:

  • 如果_Newsize比现在的size小的话,把多余的元数pop掉
  • 如果_Newsize大于现在的size的话,_Reserve负责创建不够的空间,这个时候内存会发生变化
  • _Uninitialized_default_fill_n函数负责把新增加的空间用第一个元数填充

_Reserve

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

说明:

  • max_size自己打印的时候是1073741823,所以这里只是检查了一下
  • _Grow_to函数试图增加50%的capacity的大小,如果_Count比capacity + capacity/2还大,就直接用_Count
  • _Reallocate重新分配空间,地址会发生变化

reserve

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

竟然和_Reserve差不多代码~

问题回答

测试代码:

void VECTOR_TEST::TestSizeAndCapacity()
{
    PrintSizeAndCapacity();

    m_vecTest.reserve(10);
    PrintSizeAndCapacity();

    m_vecTest.resize(5);
    PrintSizeAndCapacity();

    m_vecTest.resize(10);
    PrintSizeAndCapacity();

    m_vecTest.push_back(1);
    PrintSizeAndCapacity();

    m_vecTest.resize(5);
    PrintSizeAndCapacity();

    m_vecTest.reserve(5);
    PrintSizeAndCapacity();
}

结果:

max size: 1073741823 vector size: 0 vector capacity: 0
max size: 1073741823 vector size: 0 vector capacity: 10
max size: 1073741823 vector size: 5 vector capacity: 10
address: 035104F8
max size: 1073741823 vector size: 10 vector capacity: 10
address: 035104F8
max size: 1073741823 vector size: 11 vector capacity: 15
address: 0351A050
max size: 1073741823 vector size: 5 vector capacity: 15
address: 0351A050
max size: 1073741823 vector size: 5 vector capacity: 15
address: 0351A050

1. 为什么在release下面没有,而在debug下面报错?

看源码

2. size和capacity区别的意义是什么?

就是我们所理解的意义,size是满足动态的需求

3. resize和reserve区别的意义又是什么?

reserve和resize其实在内存分配的时候做的事情是一样的,但是reserve几乎都会发生内存分配,从而转移数据,比较耗,所以尽量用resize,这是两者区别的最大意义所在。

4. reserve会改变空间大小,那么地址会变,得去验证一下

有,看输出结果

相关标签: c++