STL string 原始碼剖析2 string物件模型
阿新 • • 發佈:2018-12-14
string物件模型
上篇剖析的string物件模型
template <class _Tp, class _Alloc> class _String_base { .... _Tp* _M_start; _Tp* _M_finish; _Tp* _M_end_of_storage; }; template <class _CharT, class _Traits, class _Alloc> class basic_string : private _String_base<_CharT,_Alloc> { ..... static const size_type nops; };
從上面的程式碼可以看到string 記憶體佈局就是三個指標,在64位下就是24位元組,但是這個版本的stl 比較老,它是stl原始碼剖析一書中對應的版本特別的老。本文接下來剖析下gcc 4.4.6 版本string物件模型 ,這個版本的string 屬於寫時拷貝的版本。
gcc 4.4.6 版本string 建構函式原始碼分析
struct _Alloc_hider : _Alloc { _Alloc_hider(_CharT* __dat, const _Alloc& __a) : _Alloc(__a), _M_p(__dat) { } _CharT* _M_p; }; template<typename _CharT, typename _Traits, typename _Alloc> class basic_string { ... mutable _Alloc_hider _M_dataplus; ... }
可以看到在 gcc 4.4.6 中string 在棧上就只有一個 char * 的指標。那麼它是如何跟它引用計數關聯起來的,可以看下面的程式碼,在構造的string 物件的時候,裡面呼叫了Ref的create 函式來構造string物件,然後通過 M_ref_data 函式返回真正的字串地址給string物件的 _M_dataplus指標。 其實總結下string真正在堆上的物件是通過 ref::create 函式來申請的,這個函式會申請 struct ref + len+1 個空間,然後使用 置位new 來首先在這個空間的最上面初始化 Ref 結構體物件,然後通過呼叫 M_ref_data 函式 物件申請的空間 p 進行加1 ,然後指標達到 char * 的位置,然後把這個位置的指標返回回去,外部的 _M_dataplus 指標接受,所以棧上的 _M_dataplus 指向的並不是string在堆上的全部空間只是一部分。
template<typename _CharT, typename _Traits, typename _Alloc>
inline basic_string<_CharT, _Traits, _Alloc>::basic_string()
: _M_dataplus(_S_construct(size_type(), _CharT(), _Alloc()), _Alloc()) {}
template<typename _CharT, typename _Traits, typename _Alloc>
template<typename _InIterator>
_CharT* basic_string<_CharT, _Traits, _Alloc>::_S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a,
input_iterator_tag)
{
...
_CharT __buf[128];
size_type __len = 0;
while (__beg != __end && __len < sizeof(__buf) / sizeof(_CharT))
{
__buf[__len++] = *__beg;
++__beg;
}
_Rep* __r = _Rep::_S_create(__len, size_type(0), __a);//這個裡呼叫了create 函式
_M_copy(__r->_M_refdata(), __buf, __len);
__try
{
while (__beg != __end)
{
if (__len == __r->_M_capacity)
{
// Allocate more space.
_Rep* __another = _Rep::_S_create(__len + 1, __len, __a);
_M_copy(__another->_M_refdata(), __r->_M_refdata(), __len);
__r->_M_destroy(__a);
__r = __another;
}
__r->_M_refdata()[__len++] = *__beg;
++__beg;
}
}
....
__r->_M_set_length_and_sharable(__len);
return __r->_M_refdata();
}
template<typename _CharT, typename _Traits , typename _Alloc>
typename basic_string <_CharT, _Traits, _Alloc >::_Rep*
basic_string<_CharT , _Traits, _Alloc>::_Rep ::
_S_create(size_type __capacity, size_type __old_capacity ,
const _Alloc & __alloc)
{
// 需要分配的空間包括:
// 一個數組 char_type[__capacity]
// 一個額外的結尾符 char_type()
// 一個足以容納 struct _Rep 空間
// Whew. Seemingly so needy, yet so elemental.
size_type __size = (__capacity + 1) * sizeof( _CharT) + sizeof (_Rep);
void* __place = _Raw_bytes_alloc (__alloc). allocate(__size ); //申請空間
_Rep * __p = new (__place) _Rep;// 在地址__place 空間上直接 new物件( 稱為placement new)
__p-> _M_capacity = __capacity ;
__p-> _M_set_sharable();// 設定引用計數為0,標明該物件只為自己所有
return __p;
}
物件模型圖
gcc 4.4.6
本部落格上篇剖析的 string 物件模型
預設存一個 字串 a 的物件模型