美文网首页
string 实现

string 实现

作者: my_passion | 来源:发表于2022-10-09 21:12 被阅读0次

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

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

    1 深拷贝下 string 实现

    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指向实际的数据
            pointer _M_p;  // The actual data.
        };
        
        // (1)
        _Alloc_hider _M_dataplus;
    
        // (2) 数据长度 <=> string::size()
        size_type _M_string_length;
        
        // 容量用枚举
        enum { _S_local_capacity = 15 / sizeof(_CharT) }; // 通常 = 15 
    
        /**
         * (3) 小技巧, 用了union: 用 _M_local_buf 与 _M_allocated_capacity 用一个时 不需要关注另一个
         */
        union {
            _CharT _M_local_buf[_S_local_capacity + 1]; // 16
    
            // 内部已分配的内存大小, <=> string::capacity()
            size_type _M_allocated_capacity;
        };
    };
    
    string 成员数据.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(): 即调用 char 类型的默认构造函数, 得 '\0', 为末尾添结束符 '\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() 区别: 没区别

    Note: '\0' 结束符在构造 string 对象时已经添加了

        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 写时拷贝 (COW) 实现: 主要是为了避免过多的拷贝

    成员数据.png

    Copy ctor

        /* Ctor: 调 _Rep 的 _M_grab 函数 */
        basic_string(const basic_string& __str, const _Alloc& __a)
            : _M_dataplus(__str._M_rep()->_M_grab(__a, __str.get_allocator() ), __a) {}
    
        /* 前面已经介绍过为什么+1,这里您应该就知道为什么-1啦 */
        _Rep* _M_rep() const _GLIBCXX_NOEXCEPT 
        { return &((reinterpret_cast<_Rep*>(_M_data()))[-1]); }
    
        /**
         * _M_grab函数决定是将引用计数+1还是拷贝一份
         * 若 _M_is_leaked() 表示不可共享, 则需 拷贝一份
         */
        _CharT* _M_grab(const _Alloc& __alloc1, const _Alloc& __alloc2) 
        {
            return (!_M_is_leaked() && __alloc1 == __alloc2) ? _M_refcopy() : _M_clone(__alloc1);
        }
    
        /* 如果引用计数小于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
        }
    
    
        /* 引用拷贝, 其实就是 引用计数+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();
        }
    

    相关文章

      网友评论

          本文标题:string 实现

          本文链接:https://www.haomeiwen.com/subject/csaoartx.html