stringのsso実装


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