GCC5 std::string新变化

自从GCC-5.1开始,std::string引入了遵从C++11标准的新实现,默认使用SSO(small string optimization)特性,禁用了写时复制(COW)引用计数机制,这也带来了与旧版本std::string的ABI兼容性问题,本篇结合GCC-5.3.0源码来分析新的std::string实现。

先来对比下GCC-5.3.0与GCC-4.8.5下basic_string类声明的区别:

// GCC-5.3.0  
template<typename _CharT, typename _Traits, typename _Alloc>
class basic_string
{
 private:
  // Use empty-base optimization: http://www.cantrip.org/emptyopt.html
  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; // The actual data.
  };

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

// GCC-4.8.5
template<typename _CharT, typename _Traits = char_traits<_CharT>,
         typename _Alloc = allocator<_CharT> >
class basic_string;
typedef basic_string<char> string;

template<typename _CharT, typename _Traits, typename _Alloc>
class basic_string
{
 private:
  struct _Rep_base
  {
    size_type _M_length;
    size_type _M_capacity;
    _Atomic_word _M_refcount;
  };

  struct _Rep : _Rep_base
  {
  };
  // Use empty-base optimization: http://www.cantrip.org/emptyopt.html
  struct _Alloc_hider : _Alloc
  {
    _Alloc_hider(_CharT* __dat, const _Alloc& __a)
        : _Alloc(__a), _M_p(__dat) { }
    _CharT* _M_p; // The actual data.
  };

  mutable _Alloc_hider _M_dataplus;
  
  _CharT* _M_data() const
  { return _M_dataplus._M_p; }

  _Rep* _M_rep() const
  { return &((reinterpret_cast<_Rep*> (_M_data()))[-1]); }
};

GCC-5.3.0下std::string中使用了三个私有成员:实际持有的数据指针_M_dataplus、数据实际大小_M_string_length、针对短小字符串优化的默认16字节大小的匿名union对应的栈上内存,因此sizeof(std::string) == 32,而且已不再采用引用计数机制,每个对象真正持有实际数据,线程安全。

而GCC-4.8.5下std::string采用了写时复制的引用计数(_Rep类),内部仅有一个实际持有的数据指针_M_dataplus,因此sizeof(std::string) == 8,而且由COW实现也可见多线程下使用不安全。

对于新的std::string实现导致的不同版本GCC编译导致的二进制不兼容问题,GCC5 提供了相应的二进制兼容宏开关_GLIBCXX_USE_CXX11_ABI。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注