sso的全称是Small String Optimization,小字符串优化。
struct _Alloc_hider : allocator_type // TODO check __is_final
{
_Alloc_hider(pointer __dat, const _Alloc& __a = _Alloc())
: allocator_type(__a), _M_p(__dat) { }
pointer _M_p;
};
_M_p就是真正的数据的指针。
_Alloc_hider _M_dataplus;
size_type _M_string_length;
enum { _S_local_capacity = 15 / sizeof(_CharT) };
union
{
_CharT _M_local_buf[_S_local_capacity + 1];
size_type _M_allocated_capacity;
};
_M_string_length是数据的长度,_M_local_buf就是预分配的小块内存,如果_CharT是char类型的话,_S_local_capacity=15,_M_local_buf的大小就是16字节,_M_allocated_capacity是当数据的大小大于预分配的小块内存的时候分配的内存大小。如果小于预分配的小块内存的大小就使用_M_local_buf,如果大于就分配新的内存,这时用到_M_allocated_capacity,它们不会并存,所以可以放到一个union里面。
默认构造函数:
basic_string() _GLIBCXX_NOEXCEPT
: _M_dataplus(_M_local_data())
{ _M_set_length(0); }
默认构造函数把小块内存的地址赋给了数据指针,并且将_M_string_length设为0.
basic_string(const basic_string& __str)
: _M_dataplus(_M_local_data(), __str._M_get_allocator())
{ _M_construct(__str._M_data(), __str._M_data() + __str.length()); }
拷贝构造函数把活都转给了_M_construct:
template<typename _InIterator>
void
_M_construct(_InIterator __beg, _InIterator __end)
{
typedef typename std::__is_integer<_InIterator>::__type _Integral;
_M_construct_aux(__beg, __end, _Integral());
}
_M_construct又把活转给了_M_construct_aux:
template<typename _InIterator>
void
_M_construct_aux(_InIterator __beg, _InIterator __end,
std::__false_type)
{
typedef typename iterator_traits<_InIterator>::iterator_category _Tag;
_M_construct(__beg, __end, _Tag());
}
因为指针不是integer,所以是__false_type.
由前面的博文我们知道指针的iterator_category是random_access_iterator_tag,派生自input_iterator_tag,于是转到了下面的函数:
template<typename _CharT, typename _Traits, typename _Alloc>
template<typename _InIterator>
void
basic_string<_CharT, _Traits, _Alloc>::
_M_construct(_InIterator __beg, _InIterator __end,
std::input_iterator_tag)
{
size_type __len = 0;
size_type __capacity = size_type(_S_local_capacity);//15
while (__beg != __end && __len < __capacity)
{
_M_data()[__len++] = *__beg;
++__beg;
}
//__beg==__end 或者__len==__capacity(即申请的栈内存已用完)
__try
{
while (__beg != __end)
{
if (__len == __capacity)//申请的栈内存已用完
{
// Allocate more space.
__capacity = __len + 1;
pointer __another = _M_create(__capacity, __len);//分配更多的内存,可能会失败
this->_S_copy(__another, _M_data(), __len);//将原来的数据拷贝到新的内存
_M_dispose();//如果以前是new出来的内存,则释放该内存;如果以前是缓存,则不用释放
_M_data(__another);//新数据的指针
_M_capacity(__capacity);//新分配的内存的大小
}
_M_data()[__len++] = *__beg;
++__beg;
}
}
__catch(...)
{
_M_dispose();//如果以前是new出来的内存,则释放该内存
__throw_exception_again;
}
_M_set_length(__len);
}
赋值操作符:
basic_string&
operator=(const basic_string& __str)
{ return this->assign(__str); }
把活转给了assign:
basic_string&
assign(const basic_string& __str)
{
this->_M_assign(__str);
return *this;
}
又转给了_M_assign:
template<typename _CharT, typename _Traits, typename _Alloc>
void
basic_string<_CharT, _Traits, _Alloc>::
_M_assign(const basic_string& __str)
{
if (this != &__str)
{
const size_type __rsize = __str.length();
const size_type __capacity = capacity();
if (__rsize > __capacity)
{
size_type __new_capacity = __rsize;
pointer __tmp = _M_create(__new_capacity, __capacity);
_M_dispose();
_M_data(__tmp);
_M_capacity(__new_capacity);
}
if (__rsize)
this->_S_copy(_M_data(), __str._M_data(), __rsize);
_M_set_length(__rsize);
}
}
析构函数:
~basic_string(){ _M_dispose(); }
void _M_dispose()
{
if (!_M_is_local())
_M_destroy(_M_allocated_capacity);
}
void
_M_destroy(size_type __size) throw()
{ _Alloc_traits::deallocate(_M_get_allocator(), _M_data(), __size + 1); }