std::string まとめ
注意
gcc version 4.3.2 の std::string 私的まとめ
実装
- クラス std::basic_string
::_Rep は以下の情報を持つ - 文字列長 _M_length
- 確保された容量 _M_capacity
- 参照カウンタ _M_refcount
- アロケータ(std::basic_string
::_Alloc)の派生クラス(std::basic_string ::_Alloc_hider)が文字列へのポインタをメンバとして持つ(_M_p) - アロケータは空のクラスであることが多く、そのための 1byte の容量を節約するため(empty base optimization)
- std::basic_string
のメンバは std::basic_string ::_Alloc_hider のインスタンス _M_dataplus だけ - つまり、 sizeof(std::string) == sizeof(char*) 無駄がない。
- std::basic_string
::_Rep は _M_dataplus._M_p が指している領域の前に確保されている(_M_dataplus._M_p を std::basic_string ::_Rep にキャストして 1 を引いた場所に確保されている)
参照カウンタの3つの状態
参照カウンタには3つの状態がある
- 共有不可能
- 共有可能
- 共有中
共有不可能
非 const なイテレータを返す操作や、文字のリファレンスを返す操作を行ったとき(begin, end, insert, operator[]) に、共有不可能なオブジェクトになる。
ポインタを外部に漏らした瞬間、そのメモリは共有できないものになるということ。
共有不可能なオブジェクトは、常にコピーが行われる。
const な文字列は共有不可能なオブジェクトにはならない。
std::string a("hoge"); const std::string b("fuga"); a.begin(); // ここで、 a は共有不可能なオブジェクトになる b.begin(); // const なら大丈夫
また、 reallocate が発生するような処理が発生したとき、また共有可能なオブジェクトに戻る。
共有可能
代入によってコピーが行われない。まだ共有されていない文字列。初期状態の文字列。
共有中
文字列データが他のオブジェクトと共有され、参照カウンタによって管理されている。