std::string存储结构与字符串结束符
2021/7/16 23:16:45
本文主要是介绍std::string存储结构与字符串结束符,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
(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中描述的。
1 2 3 4 | 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这个结构。
1 2 3 4 | // 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结构的关键,它的成员变量有三个,每个都很关键:
1 2 3 | union _Bxty _Bx; // store short buffer or store pointer size_type _Mysize; // current length of string size_type _Myres; // current storage reserved for string |
- _Bx的union结构提供16位长度内存块,存储小于16个长度时,直接使用;
- _Bx提供指针,大于等于16位长度时,分配内存放在该union结构指针里,供存储使用;
- _Mysize记录字符串长度;
- _Myres记录当前已分配资源块长度;
_String_val总体代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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存储在哪个结构中明确了,再看看使用时,就可以解答我们的一些问题了。
以下面的这个构造为例:
1 | std::string str(8, 'a') |
它会调用到basic_string的长度+字符构造函数,在这个构造函数中有两个关键的点,一个初始化字符串的_String_val结构,一个把值设入这个结构中。
1 2 3 4 5 | // std::string的长度+字符构造方式: basic_string(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) : _Mybase(){ _Tidy_init(); assign(_Count, _Ch); } |
初始化就比较简单了:字符串初始长度为0,资源先考虑用union的资源并初始化。
1 2 3 4 5 6 | 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 } |
赋值时就要考虑资源长度问题了:
- 基于资源长度,判定使用内部的union的块来存,还是申请内存来存,申请时会增加一些长度的;
- 数据设置完,最后都会再设置一个类型缺省构造上去,也就是字符结束符。我们已知对与char类型_Elem() = char() = ‘\0’,这样的话最后一位之后多设置一个_Elem()就成就了末尾带’\0’了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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::string存储结构与字符串结束符的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-12百万架构师第十五课:源码分析:Spring 源码分析:SpringMVC核心原理及源码分析|JavaGuide
- 2025-01-11有哪些好用的家政团队管理工具?
- 2025-01-11营销人必看的GTM五个指标
- 2025-01-11办公软件在直播电商前期筹划中的应用与推荐
- 2025-01-11提升组织效率:上级管理者如何优化跨部门任务分配
- 2025-01-11酒店精细化运营背后的协同工具支持
- 2025-01-11跨境电商选品全攻略:工具使用、市场数据与选品策略
- 2025-01-11数据驱动酒店管理:在线工具的核心价值解析
- 2025-01-11cursor试用出现:Too many free trial accounts used on this machine 的解决方法
- 2025-01-11百万架构师第十四课:源码分析:Spring 源码分析:深入分析IOC那些鲜为人知的细节|JavaGuide