详解当然是从源码入手了.
我们先来看看string的reserve的源码
template<typename _CharT, typename _Traits, typename _Alloc>
void
basic_string<_CharT, _Traits, _Alloc>::
reserve(size_type __res)
{
if (__res < length())
__res = length();
const size_type __capacity = capacity();
if (__res != __capacity)
{
if (__res > __capacity
|| __res > size_type(_S_local_capacity))
{
pointer __tmp = _M_create(__res, __capacity);
this->_S_copy(__tmp, _M_data(), length() + 1);
_M_dispose();
_M_data(__tmp);
_M_capacity(__res);
}
else if (!_M_is_local())
{
this->_S_copy(_M_local_data(), _M_data(), length() + 1);
_M_destroy(__capacity);
_M_data(_M_local_data());
}
}
}
首先看这三句
if (__res < length())
__res = length();
const size_type __capacity = capacity();
首先 _res 是我们的传进来的参数 先与我们string的长度对比 小于的话设置为长度 这是为了不使得string收缩 然后得到一个capacity的值
然后是一个判断语句
if (__res > __capacity
|| __res > size_type(_S_local_capacity))
因为我们上面把_res最小值已经设置为length 所以如果_res大于capacity意味着要进行扩容 但也有可能现在的数据还存放在local_capacity中 什么是local_capacity呢
enum { _S_local_capacity = 15 / sizeof(_CharT) };
union
{
_CharT _M_local_buf[_S_local_capacity + 1];
size_type _M_allocated_capacity;
};
首先_S_local_capacity大小基于_CharT _CharT是string的字符类型可能为char wchar_t u16char_t u32char_t string中初始的数据如果小于_S_local_capacity 后两个C++11以后支持 则存放在_M_local_buf中 大于的话进行扩容 存放在又一个alloctor申请的空间中 存储的形式是一个裸指针
我们再回到刚刚的判断条件的第二部 如果大于初始的容量 我们都会进行扩容
pointer __tmp = _M_create(__res, __capacity);
this->_S_copy(__tmp, _M_data(), length() + 1);
我们现在来到了这个函数最重要的部分
我们首先看第一步 即已传入的参数的大小进行扩容 如果其大于本身的length 则是参数多大就扩容多大 _M_create的参数第一个是new_capacity 第二个是old_capacity, 然后是第二步 _M_data()会返回原来的指针 所以这一步的作用是拷贝数据 把原数据拷贝到先指针上
_M_dispose();
_M_data(__tmp);
_M_capacity(__res);
这三个函数比较简单 第一个是销毁原指针 第二个是把申请的指针付给string对象 第三个是设置新容量 因为_M_create_的第一个参数是引用 所以_res会在一些条件下改变 条件如下:
if (__capacity > __old_capacity && __capacity < 2 * __old_capacity)
{
__capacity = 2 * __old_capacity;
if (__capacity > max_size())
__capacity = max_size();
}
我们再来看最后一个判断条件及其内容
else if (!_M_is_local())
{
this->_S_copy(_M_local_data(), _M_data(), length() + 1);
_M_destroy(__capacity);
_M_data(_M_local_data());
}
我们前面说道在capacity小于_S_local_capacity时我们的数据其实存放在栈中 即一个字符数组中 这一步其实就是当我们现在的length小于_S_local_capacity且其数据存储在alloctor分配的内存中 这个时候我们要做的是把数据转移到_M_local_buf中 即栈中, 然后销毁alloctor分配的内存 然后就是重新设置真实存储数据的指针为_M_local_buf (_M_local_data()返回_M_local_buf)
这样对于reserve这个函数我们算是无死角的理解了