string 實(shí)現(xiàn)

本文參考 https://zhuanlan.zhihu.com/p/267896855

// file: string
using string = basic_string<char>;

1 深拷貝下 string 實(shí)現(xiàn)

template <typename _CharT, typename _Traits, typename _Alloc>
class basic_string 
{
    // Use empty-base optimization: http://www.cantrip.org/emptyopt.html
    struct _Alloc_hider : allocator_type  // TODO check __is_final
    {
        _Alloc_hider(pointer __dat, const _Alloc& __a) : allocator_type(__a), _M_p(__dat) {}

        _Alloc_hider(pointer __dat, _Alloc&& __a = _Alloc()) : allocator_type(std::move(__a)), _M_p(__dat) {}

        // _M_p指向?qū)嶋H的數(shù)據(jù)
        pointer _M_p;  // The actual data.
    };
    
    // (1)
    _Alloc_hider _M_dataplus;

    // (2) 數(shù)據(jù)長(zhǎng)度 <=> string::size()
    size_type _M_string_length;
    
    // 容量用枚舉
    enum { _S_local_capacity = 15 / sizeof(_CharT) }; // 通常 = 15 

    /**
     * (3) 小技巧惜纸, 用了union: 用 _M_local_buf 與 _M_allocated_capacity 用一個(gè)時(shí) 不需要關(guān)注另一個(gè)
     */
    union {
        _CharT _M_local_buf[_S_local_capacity + 1]; // 16

        // 內(nèi)部已分配的內(nèi)存大小, <=> string::capacity()
        size_type _M_allocated_capacity;
    };
};
string 成員數(shù)據(jù).png

Ctor

basic_string() : _M_dataplus(_M_local_data() ) 
{ _M_set_length(0); }
const_pointer 
_M_local_data() const 
{ 
    return std::pointer_traits<const_pointer>::pointer_to(*_M_local_buf); 
}
void
_M_set_length(size_type __n)
{
    _M_length(__n);
    
    /* _charT(): 即調(diào)用 char 類型的默認(rèn)構(gòu)造函數(shù), 得 '\0', 為末尾添結(jié)束符 '\0' */
    traits_type::assign(_M_data()[__n], _CharT() );
}

Copy Ctor: 每次都做1次 深拷貝

    basic_string(const basic_string& __str)
        : _M_dataplus(_M_local_data(), 
        _Alloc_traits::_S_select_on_copy(__str._M_get_allocator() ) ) 
    {
        _M_construct(__str._M_data(), __str._M_data() + __str.length() );
    }

data() 和 c_str() 區(qū)別: 沒區(qū)別

Note: '\0' 結(jié)束符在構(gòu)造 string 對(duì)象時(shí)已經(jīng)添加了

    const _CharT* 
    c_str() const _GLIBCXX_NOEXCEPT 
    { return _M_data(); }

    const _CharT* 
    data() const _GLIBCXX_NOEXCEPT 
    { return _M_data(); }
    pointer
    _M_data() const
    { return _M_dataplus._M_p; }

2 string 寫時(shí)拷貝 (COW) 實(shí)現(xiàn): 主要是為了避免過多的拷貝

成員數(shù)據(jù).png

Copy ctor

    /* Ctor: 調(diào) _Rep 的 _M_grab 函數(shù) */
    basic_string(const basic_string& __str, const _Alloc& __a)
        : _M_dataplus(__str._M_rep()->_M_grab(__a, __str.get_allocator() ), __a) {}

    /* 前面已經(jīng)介紹過為什么+1怎爵,這里您應(yīng)該就知道為什么-1啦 */
    _Rep* _M_rep() const _GLIBCXX_NOEXCEPT 
    { return &((reinterpret_cast<_Rep*>(_M_data()))[-1]); }

    /**
     * _M_grab函數(shù)決定是將引用計(jì)數(shù)+1還是拷貝一份
     * 若 _M_is_leaked() 表示不可共享, 則需 拷貝一份
     */
    _CharT* _M_grab(const _Alloc& __alloc1, const _Alloc& __alloc2) 
    {
        return (!_M_is_leaked() && __alloc1 == __alloc2) ? _M_refcopy() : _M_clone(__alloc1);
    }

    /* 如果引用計(jì)數(shù)小于0, 則為 true, 前面有過約定 */
    bool _M_is_leaked() const _GLIBCXX_NOEXCEPT 
    {
    #if defined(__GTHREADS)
        // _M_refcount is mutated concurrently by _M_refcopy/_M_dispose,
        // so we need to use an atomic load. However, _M_is_leaked
        // predicate does not change concurrently (i.e. the string is either
        // leaked or not), so a relaxed load is enough.
        return __atomic_load_n(&this->_M_refcount, __ATOMIC_RELAXED) < 0;
    #else
        return this->_M_refcount < 0;
    #endif
    }


    /* 引用拷貝, 其實(shí)就是 引用計(jì)數(shù)+1 */
    _CharT* _M_refcopy() throw() {
    #if _GLIBCXX_FULLY_DYNAMIC_STRING == 0
        if (__builtin_expect(this != &_S_empty_rep(), false))
    #endif
            __gnu_cxx::__atomic_add_dispatch(&this->_M_refcount, 1);
        return _M_refdata();
    }  // XXX MT

    /* 深拷貝 */
    template <typename _CharT, typename _Traits, typename _Alloc>
    _CharT* basic_string<_CharT, _Traits, _Alloc>::_Rep::_M_clone(const _Alloc& __alloc, size_type __res) 
    {
        // Requested capacity of the clone.
        const size_type __requested_cap = this->_M_length + __res;
        _Rep* __r = _Rep::_S_create(__requested_cap, this->_M_capacity, __alloc);
        if (this->_M_length) _M_copy(__r->_M_refdata(), _M_refdata(), this->_M_length);

        __r->_M_set_length_and_sharable(this->_M_length);
        return __r->_M_refdata();
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末徙瓶,一起剝皮案震驚了整個(gè)濱河市梢夯,隨后出現(xiàn)的幾起案子呛谜,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件犀填,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡嗓违,警方通過查閱死者的電腦和手機(jī)九巡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹂季,“玉大人冕广,你說我怎么就攤上這事〕ソ啵” “怎么了撒汉?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)父能。 經(jīng)常有香客問我,道長(zhǎng)净神,這世上最難降的妖魔是什么何吝? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮鹃唯,結(jié)果婚禮上爱榕,老公的妹妹穿的比我還像新娘。我一直安慰自己坡慌,他們只是感情好黔酥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著洪橘,像睡著了一般跪者。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上熄求,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天渣玲,我揣著相機(jī)與錄音,去河邊找鬼弟晚。 笑死忘衍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的卿城。 我是一名探鬼主播枚钓,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼瑟押!你這毒婦竟也來了搀捷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤多望,失蹤者是張志新(化名)和其女友劉穎指煎,沒想到半個(gè)月后蹋偏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡至壤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年威始,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片像街。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡黎棠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出镰绎,到底是詐尸還是另有隱情脓斩,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布畴栖,位于F島的核電站随静,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏吗讶。R本人自食惡果不足惜燎猛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望照皆。 院中可真熱鬧重绷,春花似錦、人聲如沸膜毁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瘟滨。三九已至候醒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間杂瘸,已是汗流浹背火焰。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胧沫,地道東北人昌简。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像绒怨,于是被迫代替她去往敵國(guó)和親纯赎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容