std::string

对于vc的std::string:

basic_string中:
enum{  _BUF_SIZE = 16 / sizeof (_Elem) < 1 ? 1 : 16 / sizeof(_Elem)};
union _Bxty
{
_Elem  _Buf[_BUF_SIZE];
_Elem* _Ptr;
} _Bx
通过这个union可以看出vc的std::string在字符串长度较小的时候会使用一个栈上缓冲区(_Bxty::_Buf)来保存字符串内容,如果字符串长度超过了某个范围则会使用allocator分配动态内存(_Bxty::_Ptr),_BUF_SIZE控制着这个范围值,_Buf缓冲区始终是 16个字节大小。

看看成员函数c_str()
 const _Elem *c_str() const
        {    // return pointer to null-terminated nonmutable array
        return (_Myptr());
        }


    const _Elem *_Myptr() const
        {    // determine current pointer to buffer for nonmutable string
        return (this->_BUF_SIZE <= this->_Myres ? this->_Bx._Ptr
            : this->_Bx._Buf);
        }
如果a是一个很短的string,那么它将会放到栈里(调试器显示_Ptr是Bad_Ptr,而数据是放到了_Buf里)。进行a=AnotherString赋值时,如果AnotherString过长,将会被放到_Ptr指向的地址,如果还是很短,会继续在_Buf指向的栈的地址往后写。 
如果a是一个较长的string(长到没有被放到栈里),进行a=AnotherString赋值时,AnotherString是一个更长的字符串,则如果比原串只是长一点,就会直接在原地址覆盖(看来是在初始化时就已经申请了一个大于原string的空间。)。但是比原字符串长很多(多申请的空间还是不够)原字符串会被释放,然后重新申请一个足够大的空间来存放新字符串。 

可以看出,vc的std::string没有使用通用Copy-On-Write技术,因为它没有reference count成员。

SGI STL string 中使用三个位置变量标志内存区域
_Tp* _M_start;
_Tp* _M_finish;
_Tp* _M_end_of_storage;

并且使用模板技术提供相应的分配器来分配内存



alloc.h中包含了几种分配器,如下:

using __STD::__malloc_alloc_template; 
using __STD::malloc_alloc; 
using __STD::simple_alloc; 
using __STD::debug_alloc; 
using __STD::__default_alloc_template; 
using __STD::alloc; 
using __STD::single_client_alloc; 
#ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG
using __STD::__malloc_alloc_oom_handler; 
#endif /* __STL_STATIC_TEMPLATE_MEMBER_BUG */
#ifdef __STL_USE_STD_ALLOCATORS 
using __STD::allocator;

具体的分配器类的定义可以在SGI的STL的stl_alloc.h中找到。例如默认的C++标准分配器:

#ifdef __STL_USE_STD_ALLOCATORS

template 
class allocator {
  typedef alloc _Alloc;          // The underlying allocator.
public:
  typedef size_t     size_type;
  typedef ptrdiff_t  difference_type;
  typedef _Tp*       pointer;
  typedef const _Tp* const_pointer;
  typedef _Tp&       reference;
  typedef const _Tp& const_reference;
  typedef _Tp        value_type;

  template  struct rebind {
    typedef allocator<_Tp1> other;
  };

  allocator() __STL_NOTHROW {}
  allocator(const allocator&) __STL_NOTHROW {}
  template  allocator(const allocator<_Tp1>&) __STL_NOTHROW {}
  ~allocator() __STL_NOTHROW {}

  pointer address(reference __x) const { return &__x; }
  const_pointer address(const_reference __x) const { return &__x; }

  // __n is permitted to be 0.  The C++ standard says nothing about what
  // the return value is when __n == 0.
  _Tp* allocate(size_type __n, const void* = 0) {
    return __n != 0 ? static_cast<_Tp*>(_Alloc::allocate(__n * sizeof(_Tp))) 
                    : 0;
  }

  // __p is not permitted to be a null pointer.
  void deallocate(pointer __p, size_type __n)
    { _Alloc::deallocate(__p, __n * sizeof(_Tp)); }

  size_type max_size() const __STL_NOTHROW 
    { return size_t(-1) / sizeof(_Tp); }

  void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }
  void destroy(pointer __p) { __p->~_Tp(); }
};
根据C++的标准,STL的allocator,把对象的申请和释放分成了4步:
第1步:申请内存空间,对应函数是allocator::allocate()
第2步:执行构造函数,对应函数是allocator::construct()
第3步:执行析构函数,对应函数是allocator::destroy()
第4步:释放内存空间,对应函数是allocator::deallocate()

从上面的代码中可以看到这四个函数的定义。

你可能感兴趣的:(C/C++)