对于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 _Tp> 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 <class _Tp1> struct rebind { typedef allocator<_Tp1> other; }; allocator() __STL_NOTHROW {} allocator(const allocator&) __STL_NOTHROW {} template <class _Tp1> 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()
从上面的代码中可以看到这四个函数的定义。