std::string实现原理1

来源:互联网 发布:淘宝特卖入口 编辑:程序博客网 时间:2024/05/16 13:57

std::string


对于vc的std::string:

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

看看成员函数c_str()
[cpp] view plaincopy
  1. const _Elem *c_str() const  
  2.        {    // return pointer to null-terminated nonmutable array  
  3.        return (_Myptr());  
  4.        }  
  5.   
  6.   
  7.    const _Elem *_Myptr() const  
  8.        {    // determine current pointer to buffer for nonmutable string  
  9.        return (this->_BUF_SIZE <= this->_Myres ? this->_Bx._Ptr  
  10.            : this->_Bx._Buf);  
  11.        }  
如果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中包含了几种分配器,如下:

[cpp] view plaincopy
  1. using __STD::__malloc_alloc_template;   
  2. using __STD::malloc_alloc;   
  3. using __STD::simple_alloc;   
  4. using __STD::debug_alloc;   
  5. using __STD::__default_alloc_template;   
  6. using __STD::alloc;   
  7. using __STD::single_client_alloc;   
  8. #ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG  
  9. using __STD::__malloc_alloc_oom_handler;   
  10. #endif /* __STL_STATIC_TEMPLATE_MEMBER_BUG */  
  11. #ifdef __STL_USE_STD_ALLOCATORS   
  12. using __STD::allocator;  

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

[cpp] view plaincopy
  1. #ifdef __STL_USE_STD_ALLOCATORS  
  2.   
  3. template <class _Tp>  
  4. class allocator {  
  5.   typedef alloc _Alloc;          // The underlying allocator.  
  6. public:  
  7.   typedef size_t     size_type;  
  8.   typedef ptrdiff_t  difference_type;  
  9.   typedef _Tp*       pointer;  
  10.   typedef const _Tp* const_pointer;  
  11.   typedef _Tp&       reference;  
  12.   typedef const _Tp& const_reference;  
  13.   typedef _Tp        value_type;  
  14.   
  15.   template <class _Tp1> struct rebind {  
  16.     typedef allocator<_Tp1> other;  
  17.   };  
  18.   
  19.   allocator() __STL_NOTHROW {}  
  20.   allocator(const allocator&) __STL_NOTHROW {}  
  21.   template <class _Tp1> allocator(const allocator<_Tp1>&) __STL_NOTHROW {}  
  22.   ~allocator() __STL_NOTHROW {}  
  23.   
  24.   pointer address(reference __x) const { return &__x; }  
  25.   const_pointer address(const_reference __x) const { return &__x; }  
  26.   
  27.   // __n is permitted to be 0.  The C++ standard says nothing about what  
  28.   // the return value is when __n == 0.  
  29.   _Tp* allocate(size_type __n, const void* = 0) {  
  30.     return __n != 0 ? static_cast<_Tp*>(_Alloc::allocate(__n * sizeof(_Tp)))   
  31.                     : 0;  
  32.   }  
  33.   
  34.   // __p is not permitted to be a null pointer.  
  35.   void deallocate(pointer __p, size_type __n)  
  36.     { _Alloc::deallocate(__p, __n * sizeof(_Tp)); }  
  37.   
  38.   size_type max_size() const __STL_NOTHROW   
  39.     { return size_t(-1) / sizeof(_Tp); }  
  40.   
  41.   void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }  
  42.   void destroy(pointer __p) { __p->~_Tp(); }  
  43. };  
根据C++的标准,STL的allocator,把对象的申请和释放分成了4步:
第1步:申请内存空间,对应函数是allocator::allocate()
第2步:执行构造函数,对应函数是allocator::construct()
第3步:执行析构函数,对应函数是allocator::destroy()
第4步:释放内存空间,对应函数是allocator::deallocate()

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

参考:

string _myptr  百度

0 0
原创粉丝点击