ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

std::string存储结构与字符串结束符

2021-07-16 22:30:43  阅读:291  来源: 互联网

标签:std Count const string basic 结束符 type size


(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
参考:std::string源码
参考:https://www.cplusplus.com/reference/string/string/

std::string确实是一个很棒的类结构。之前使用时,还在想,std::string如何保存末尾的字符串结束符,std::wstring时呢又是如何;一般在vs上调试查看时并没有看到字符串结束符啊;另外结束符算不算到size里面去呢,要算到分配的空间里面去吧;带着这些疑问,去看下string的源码,就会比较清楚了。

1. 概念:字符末尾结束符==末尾类型缺省构造

先提一个概念转换:
末尾添加结束符 转化为 末尾添加一个类型的缺省构造

使用类型的缺省构造 char() wchar_t() char16_t() char32_t() 的值都为0,类型的缺省构造也就字符串的结束符了。

所以末尾添加一个类型的缺省构造,对字符而言,就是添加了结束符啊。
这种方式后续自己写代码的时候,也可以利用;
概念转变了,思路也就打开了。

2. basic_string存储

string来源于basic_string,算是这个模版类的一个实例,主要的功能实现也都在basic_string中描述的。

typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
typedef basic_string<char16_t> u16string;
typedef basic_string<char32_t> u32string;

2.1 存储的成员变量

std::string存储的变量:_Mypair;_Compressed_pair该结构封装了两个值的访问,没有特殊的用途。对于string存储而言,重点关注_String_val这个结构。

// using _Alty = typename _Alloc_types::_Alty;
// using _Val_types = typename _Alloc_types::_Val_types;
using _Mydata_t = _String_val<_Val_types>;
_Compressed_pair<_Alty, _Mydata_t> _Mypair;

2.2 _String_val结构定义

_String_val的结构定义:这个结构是了解string结构的关键,它的成员变量有三个,每个都很关键:

union _Bxty _Bx;    // store short buffer or store pointer
size_type _Mysize;  // current length of string
size_type _Myres;   // current storage reserved for string
  1. _Bx的union结构提供16位长度内存块,存储小于16个长度时,直接使用;
  2. _Bx提供指针,大于等于16位长度时,分配内存放在该union结构指针里,供存储使用;
  3. _Mysize记录字符串长度;
  4. _Myres记录当前已分配资源块长度;

_String_val总体代码:

template<class _Val_types>
class _String_val : public _Container_base
{ // base class for basic_string to hold data
public:
      _String_val() : _Bx(), _Mysize(0), _Myres(0) {}
      value_type *_Myptr() {
           value_type *_result = _Bx._Buf;  
           if(_Large_string_engaged()) _result = _Unfancy(_Bx._Ptr);
           return _result;
      }
      const value_type *_Myptr() const ....
      bool _Large_string_engaged() const { return (_BUF_SIZE <= _Myres); }
      void _Check_offset(const size_type off) const { if (_Mysize < _Off) _Xran(); }
      void _Check_offset_exclusize(const size_type _Off) const { if (_Mysize <= _Off) _Xran();}
      static void _Xran(){ _Xout_of_range("Invalid string position"); }
      size_type _Clamp_suffix_size(const size_type _Off, const size_type _Size) const noexcept { return (_Min_value(_Size, _Mysize - _Off)); }
     // variables
     enum { _BUF_SIZE = 16 / (sizeof(value_type) < 1 ? 1 : 16 / sizeof(value_type)) }
     enum { _ALLOC_MASK = sizeof(value_type) <= 1 ? 15 : sizeof (value_type) <= 2 ? 7 : sizeof(value_type) <=4 ? 3 : sizeof(value_type <= 8)? 1: 0 };
     union _Bxty{ // storage for small
         _Bxty = defaut;   ~_Bxty = default();
         value_type _Buf[_BUF_SIZE];
         pointer _Ptr;
         char _Alias[_BUF_SIZE];
     } _Bx;
     size_type _Mysize;  // current length of string
     size_type _Myres;   // current storage reserved for string
}

3. std::string存储使用

string存储在哪个结构中明确了,再看看使用时,就可以解答我们的一些问题了。
以下面的这个构造为例:

std::string str(8, 'a')

它会调用到basic_string的长度+字符构造函数,在这个构造函数中有两个关键的点,一个初始化字符串的_String_val结构,一个把值设入这个结构中。

// std::string的长度+字符构造方式:
basic_string(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) : _Mybase(){
    _Tidy_init();
    assign(_Count, _Ch);
}

初始化就比较简单了:字符串初始长度为0,资源先考虑用union的资源并初始化。

void _Tidy_init(){
    auto &_My_data = this->_Get_data(); // 获取到_String_val
    _My_data._Mysize = 0; // 字符长度设0
    _My_data._Myres = this->_BUF_SIZE - 1; // 资源长度设15
    _Traits::assign(_My_data._Bx._Buf[0], _Elem());   // 资源首字符设\0
}

赋值时就要考虑资源长度问题了:

  1. 基于资源长度,判定使用内部的union的块来存,还是申请内存来存,申请时会增加一些长度的;
  2. 数据设置完,最后都会再设置一个类型缺省构造上去,也就是字符结束符。我们已知对与char类型_Elem() = char() = ‘\0’,这样的话最后一位之后多设置一个_Elem()就成就了末尾带’\0’了。
basic_string::assign(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch){ // assign _Count * _ch
    auto &_My_data = this->_Get_data();
    if (_Count < _My_data._Myres){
        _Elem* const _Old_ptr = _My_data._Myptr();
        _My_data._Mysize = _Count;
        _Traits::assign(_Old_ptr, _Count, _ch);
        _Traits::assign(_Old_ptr[_Count], _Elem());
        return (*this);
    }
    return (_Reallocate_for(_Count, [](Elem* const _New_ptr, const size_type _Count, const _Elem _ch){
        _Traits::assign(_New_ptr, _Count, _ch);
        _Traits::assign(_New_ptr[_Count], _Elem());}, _Ch);
    }
}

(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

标签:std,Count,const,string,basic,结束符,type,size
来源: https://blog.csdn.net/chunyexiyu/article/details/118824421

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有