測大小
這里我們比較4種版本的basic_string模版類,分別是:string
, wstring
, u16string
, u32string
. 雖然他們是不同的字符串類型,但是其sizeof的結果卻一樣,都為40字節(x64下):
看源碼
我們都知道,上面4個不同的類型是同一份模版(basic_string)的實例化,因此它們的內存模型都是相同的。 這里我們來追蹤一下string類型的源代碼,源碼引用VS2013版的標准string庫。
看繼承
看得出,basic_string的繼承體系非常復雜(當前無關部分我用...
代替了)。
1. typedef basic_string<char, char_traits<char>, allocator<char> >
string;
↓↓↓
2. class basic_string
: public _String_alloc<!is_empty<_Alloc>::value,
_String_base_types<_Elem, _Alloc> > {...}
↓↓↓
3. class _String_alloc
: public _String_val<typename _Alloc_types::_Val_types> {...}
↓↓↓
4. class _String_val
: public _Container_base {...}
↓↓↓
5. typedef _Container_base12 _Container_base;
↓↓↓
6. struct _Container_base12 {...}
看成員
光有繼承體系還不夠,我們還得看看類成員。 注意,這里不需要關心模版參數,至於為什么,你們自己好好想想嘍 >-<)
看定義
能夠看到,_Container_base12
類只包含一個指針(指向一個代理類,這里我們不深究),大小永遠為1個字長。 因此,我們主要來看看_String_val
類的成員定義:
1. enum
{ // length of internal buffer, [1, 16]
_BUF_SIZE = 16 / sizeof (value_type) < 1 ? 1
: 16 / sizeof (value_type)};
union _Bxty
{ // storage for small buffer or pointer to larger one
value_type _Buf[_BUF_SIZE];
pointer _Ptr;
char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;
2. size_type _Mysize; // current length of string
3. size_type _Myres; // current storage reserved for string
其中,_BUF_SIZE
定義了緩沖區的長度:
- 若value_type類型小於1字節,則 _BUF_SIZE = 16。
- 否則,_BUF_SIZE = 16 / sizeof(value_type)。(留心,這里是整除取商!!!)
析類型
這里有幾個類型定義非常重要:value_type
, pointer
, size_type
。 從源代碼上看,這些類型經過了一層又一層的typedef,源頭難辨。 因此,我們轉而從標准草案來先解讀value_type
:
typedef typename traits::char_type value_type;
X::char_type -> charT
charT -> char
其它兩個類型也依理分析,最后得出它們的實際類型分別為:
得結果
綜上,字符串類型內存模型如下:
最后讓我們拿string類型來驗證一下(><良心保證,下圖為代碼運行結果,非純數字打印):