STL 的 string 分析(二)

#-string #-STL

函数 _M_construct_null 在 __p 所在位置上构造一个空元素。

  void _M_construct_null(_CharT* __p) {
    construct(__p);
#   ifdef __STL_DEFAULT_CONSTRUCTOR_BUG
    __STL_TRY {
      *__p = (_CharT) 0;
    }
    __STL_UNWIND(destroy(__p));
#   endif
  }

函数 _M_null 返回 _CharT 类型的空值。

  static _CharT _M_null() {
#   ifndef __STL_DEFAULT_CONSTRUCTOR_BUG
    return _CharT();
#   else
    return (_CharT) 0;
#   endif
  }

函数 _M_terminate_string 在 _M_finish 的位置上设置空元素作为结束标记。

  void _M_terminate_string() {
    __STL_TRY {
      _M_construct_null(_M_finish);
    }
    __STL_UNWIND(destroy(_M_start, _M_finish));
  }

函数 _M_range_initialized 用 __f 到 __l 之间的内容初始化当前 basic_string 。函数先分配 8 个元素所需的空间,然后调用 append 函数将 __f 到 __l 之间的元素插入到当前 basic_string 的尾部。第四个标记表示迭代器类型为 input_itertor_tag 。

  template <class _InputIter>
  void _M_range_initialize(_InputIter __f, _InputIter __l,
			   input_iterator_tag) {
    _M_allocate_block(8);
    _M_construct_null(_M_finish);
    __STL_TRY {
      append(__f, __l);
    }
    __STL_UNWIND(destroy(_M_start, _M_finish + 1));
  }

函数 _M_range_initialize 用 __f 到 __l 之间的内容初始化当前 basic_string 。函数首先计算 __f 到 __l 之间一共有多少个元素。然后为当前 basic_string 分配能够容纳 __n + 1 个元素的空间,在调用 unintialized_copy 将 __f 到 __l 之间的内容复制到新分配的空间上。并调用 _M_terminate_string 在 _M_finish 所在的位置上设置空元素作为结束标记。

  template <class _ForwardIter>
  void _M_range_initialize(_ForwardIter __f, _ForwardIter __l, 
			   forward_iterator_tag) {
    difference_type __n = 0;
    distance(__f, __l, __n);
    _M_allocate_block(__n + 1);
    _M_finish = uninitialized_copy(__f, __l, _M_start);
    _M_terminate_string();
  }

_M_range_initialize 用 __f 到 __l 之间的内容初始化当前 basic_string 。

  template <class _InputIter>
  void _M_range_initialize(_InputIter __f, _InputIter __l) {
    typedef typename iterator_traits<_InputIter>::iterator_category _Category;
    _M_range_initialize(__f, __l, _Category());
  }

函数 begin() 返回 _M_start 所在的地址,函数 end() 返回 _M_finish 所在的地址。(basic_string 中 iterator 为 value_type* 的类型别名,而 _M_start 为 value_type* 类型的。

  iterator begin()             { return _M_start; }
  iterator end()               { return _M_finish; }

函数 size 返回 basic_string 中的元素个数。函数 length 也是返回 basic_string 中的元素个数。

  size_type size() const { return _M_finish - _M_start; }
  size_type length() const { return size(); }

函数 resize 重新设定 basic_string 的元素个数。如果当前 basic_string 的元素个数大于指定的个数 __n ,则将最后面多余的元素删除,以使得 basic_string 的元素个数正好为 __n。如果当前 basic_string 的元素个数小于指定的个数 __n ,则在 basic_string 的后面插入 __n - size() 个值为 __c 的元素。

  void resize(size_type __n, _CharT __c) {
    if (__n <= size())
      erase(begin() + __n, end());
    else
      append(__n - size(), __c);
  }

如果 resize 只是指定 basic_string 需要调整的大小,而没有设定当需要添加新元素以使得 basic_string 的大小达到指定值时新元素的值,那么即将 _M_null() 的返回值作为新元素添加到 basic_string 中。

  void resize(size_type __n) { resize(__n, _M_null()); }

函数 capacity 返回当前 basic_string 能容纳多少个元素。

  size_type capacity() const { return (_M_end_of_storage - _M_start) - 1; }

函数 clear 将当前 basic_string 清空,函数首先在 _M_start 所在的位置上设置结束标记,并将 _M_start + 1 到 _M_finish + 1 之间的元素销毁,并更新 _M_finish 的值为 _M_start 。

  void clear() {
    if (!empty()) {
      _Traits::assign(*_M_start, _M_null());
      destroy(_M_start+1, _M_finish+1);
      _M_finish = _M_start;
    }
  } 

函数 empty 返回当前 basic_string 是否为空。

  bool empty() const { return _M_start == _M_finish; }    

函数 operator[] 返回 basic_string 中的第 __n 个元素。函数不对指定位置 __n 的合理性进行检测。

  reference operator[](size_type __n)
    { return *(_M_start + __n); }

函数 at 返回 basic_string 中的第 __n 个元素。函数会对指定位置 __n 的合理性进行检测(size_type 是无符号整数,始终为正值)。如果 __n 大于或者等于 size(),索引越界则抛出一个异常。

  reference at(size_type __n) {
    if (__n >= size())
      _M_throw_out_of_range();
    return *(_M_start + __n);
  }

函数 operator+= 有三种定义,第一种定义将一个给定 basic_string 类型的变量 __s 中的内容插入到当前 basic_string 的尾部,第二个定义将从 __s 开始到结束标记位置的空间中的内容插入到当前 basic_string 的尾部。第三个定义将一个给定字符 __c 插入到当前 basic_string 的尾部。

  basic_string& operator+=(const basic_string& __s) { return append(__s); }
  basic_string& operator+=(const _CharT* __s) { return append(__s); }
  basic_string& operator+=(_CharT __c) { push_back(__c); return *this; }

函数 reserve 用来重新为 basic_string 分配空间,令 __n 为 max(__res_arg, size()) + 1 。然后调用基类的 _M_allocate(__n) 函数分配足够的空间,用 __new_start 暂存新分配空间的首地址,再将 basic_string 原来空间上的元素复制到新空间中来,最后更新 _M_start, _M_finish, _M_end_of_storage的值。

void basic_string<_CharT,_Traits,_Alloc>::reserve(size_type __res_arg) {
  if (__res_arg > max_size())
    _M_throw_length_error();

  size_type __n = max(__res_arg, size()) + 1;
  pointer __new_start = _M_allocate(__n);
  pointer __new_finish = __new_start;

  __STL_TRY {
    __new_finish = uninitialized_copy(_M_start, _M_finish, __new_start);
    _M_construct_null(__new_finish);
  }
  __STL_UNWIND((destroy(__new_start, __new_finish), 
		_M_deallocate(__new_start, __n)));

  destroy(_M_start, _M_finish + 1);
  _M_deallocate_block();
  _M_start = __new_start;
  _M_finish = __new_finish;
  _M_end_of_storage = __new_start + __n;
}

函数 append 将 __n 个值为 __c 的元素插入 basic_string 的后面。如果当前 basic_string 的剩余位置不足以容纳 __n 个新元素,则调用 reserve 函数重新为 basic_string 分配足够的空间,如果 size() > n ,则分配 2 倍 size() 大小的空间,否则分配 size() + __n 大小的空间。reserve 中不仅会分配新的空间,而且会将原先 basic_string 中已有的元素也复制到新空间上。然后调用 uninitialized_fill_n 在 _M_finish + 1 和 _M_finish + 1 之后的 __n - 1 为位置上填充值为 __c 的新元素(这里没有直接从 _M_finish 开始,是为了保证当出现异常是 _M_finish 所在的位置仍然还有结束标记。然后在 _M_finish + n 的位置上设置一个新的结束标记,并将 _M_finish 所在的位置上的值也设置为 __c 。更新 _M_finish 。

template <class _CharT, class _Traits, class _Alloc> 
basic_string<_CharT,_Traits,_Alloc>& 
basic_string<_CharT,_Traits,_Alloc>::append(size_type __n, _CharT __c) {
  if (__n > max_size() || size() > max_size() - __n)
    _M_throw_length_error();
  if (size() + __n > capacity())
    reserve(size() + max(size(), __n));
  if (__n > 0) {
    uninitialized_fill_n(_M_finish + 1, __n - 1, __c);
    __STL_TRY {
      _M_construct_null(_M_finish + __n);
    }
    __STL_UNWIND(destroy(_M_finish + 1, _M_finish + __n));
    _Traits::assign(*_M_finish, __c);
    _M_finish += __n;
  }
  return *this;
}

函数 append 将 __first 到 __last 之间的内容插入到 basic_string 的后面。 第三个形参限定了 __first 为 input_iterator 类型。

template <class _Tp, class _Traits, class _Alloc> 
template <class _InputIterator>
basic_string<_Tp, _Traits, _Alloc>& 
basic_string<_Tp, _Traits, _Alloc>::append(_InputIterator __first, 
					  _InputIterator __last,
					  input_iterator_tag) {
  for ( ; __first != __last ; ++__first)
    push_back(*__first);
  return *this;
}

函数 append 将 __first 到 __last 之间的内容插入到当前 basic_string 的后面。函数首先查看当前 basic_string 中剩余位置是否足以容纳 __n 个新元素,如果不能,则调用 _M_allocate 分配足够容纳新元素的空间。新分配的空间至少是原来空间的两倍。将新分配的空间的首地址暂存在 __new_start 中,将原先 basic_string 中的元素(_M_start 到 _M_finish 之间的元素) 复制到 __new_start 开始的地方。然后再将 __first 到 __last 之间的元素复制到后面。最后释放 _M_start 到 _M_end_of_storage 之间的空间。并更新 _M_start, _M_finish, _M_end_of_storage 的值。

如果 basic_string 中剩余的位置足以容纳 __n 个新元素,则将 __first + 1 到 __last 之间的元素复制到 _M_finish + 1 开始的位置,然后在 _M_finish + n 的位置上设置结束标记,这里之所以不直接从 _M_finish 开始复制也是为了保证当复制出现异常是 _M_finish 上还保留有结束标记。最后将 _M_finish 所在位置的值更新为 __first 所在位置的元素的值,并更新 _M_finish 的值。

template <class _Tp, class _Traits, class _Alloc> 
template <class _ForwardIter>
basic_string<_Tp, _Traits, _Alloc>& 
basic_string<_Tp, _Traits, _Alloc>::append(_ForwardIter __first, 
					   _ForwardIter __last,
					   forward_iterator_tag) {
  if (__first != __last) {
    const size_type __old_size = size();
    difference_type __n = 0;
    distance(__first, __last, __n);
    if (static_cast<size_type>(__n) > max_size() ||
	__old_size > max_size() - static_cast<size_type>(__n))
      _M_throw_length_error();
    if (__old_size + static_cast<size_type>(__n) > capacity()) {
      const size_type __len = __old_size +
			    max(__old_size, static_cast<size_type>(__n)) + 1;
      pointer __new_start = _M_allocate(__len);
      pointer __new_finish = __new_start;
      __STL_TRY {
	__new_finish = uninitialized_copy(_M_start, _M_finish, __new_start);
	__new_finish = uninitialized_copy(__first, __last, __new_finish);
	_M_construct_null(__new_finish);
      }
      __STL_UNWIND((destroy(__new_start,__new_finish),
		    _M_deallocate(__new_start,__len)));
      destroy(_M_start, _M_finish + 1);
      _M_deallocate_block();
      _M_start = __new_start;
      _M_finish = __new_finish;
      _M_end_of_storage = __new_start + __len; 
    }
    else {
      _ForwardIter __f1 = __first;
      ++__f1;
      uninitialized_copy(__f1, __last, _M_finish + 1);
      __STL_TRY {
	_M_construct_null(_M_finish + __n);
      }
      __STL_UNWIND(destroy(_M_finish + 1, _M_finish + __n));
      _Traits::assign(*_M_finish, *__first);
      _M_finish += __n;
    }
  }
  return *this;  
}

函数 append 将根据 __first 的类型来调用 _M_append_dispatch 的不同定义。如果 __first 的类型为整型,则将 _M_append_diaptch 会将 __first 个值为 __last 的元素插入到 basic_string 的后面,如果 __first 的类型不为整型,则 _M_append_dispatch 会将 __first 到 __last 之间的内容插入到当前 basic_string 的后面。用 _InputIter 实例化 _Is_Integer,如果 _Is_Integer<_InputIter>::Integral 是 __true_type 则表示 _InputIter 为整型,否则(为 __false_type ) 表示 _InputIter 的类型不为整型。

  template <class _InputIter>
  basic_string& append(_InputIter __first, _InputIter __last) {
    typedef typename _Is_integer<_InputIter>::_Integral _Integral;
    return _M_append_dispatch(__first, __last, _Integral());
  }

函数 _M_append_dispatch 将 __n 个值为 __x 的元素插入到 basic_string 的后面。

  template <class _Integer>
  basic_string& _M_append_dispatch(_Integer __n, _Integer __x, __true_type) {
    return append((size_type) __n, (_CharT) __x);
  }

函数 _M_append_dispatch 将从 __f 到 __l 之间的元素插入到 basic_string 的后面。

  template <class _InputIter>
  basic_string& _M_append_dispatch(_InputIter __f, _InputIter __l,
				   __false_type) {
    typedef typename iterator_traits<_InputIter>::iterator_category _Category;
    return append(__f, __l, _Category());
  }

函数 append 将给定 basic_string 的变量 __s 中的内容复制到当前 basic_string 的后面,调用之前定义的 append 定义进行实现。

  basic_string& append(const basic_string& __s) 
    { return append(__s.begin(), __s.end()); }

函数 append 将给定 basic_string __s 中从 __pos 开始的 __n 个元素复制到当前 basic_string 的后面。也是调用之前的 append 定义进行实现。

  basic_string& append(const basic_string& __s,
		       size_type __pos, size_type __n)
  {
    if (__pos > __s.size())
      _M_throw_out_of_range();
    return append(__s.begin() + __pos,
		  __s.begin() + __pos + min(__n, __s.size() - __pos));
  }

函数 append 将从 __s 开始的 __n 个元素复制到当前 basic_string 的后面。调用之前定义的 append 进行实现。

  basic_string& append(const _CharT* __s, size_type __n) 
    { return append(__s, __s+__n); }

函数 append 将 __s 开始到结束标记所在位置之间的元素复制到当前 basic_string 的后面。

  basic_string& append(const _CharT* __s) 
    { return append(__s, __s + _Traits::length(__s)); }

STL 的 string 分析(一)</br> STL 的 string 分析(二)</br> STL 的 string 分析(三)</br> STL 的 string 分析(四)</br> STL 的 string 分析(五)</br> STL 的 string 分析(六)</br>