当前位置:   article > 正文

【C++】深度解析:用 C++ 模拟实现 string 类,探索其底层实现细节

【C++】深度解析:用 C++ 模拟实现 string 类,探索其底层实现细节

目录

了解string类

string的内存管理

VS下string的结构

​g++下string的结构

 string的模拟实现

string的构造函数

 浅拷贝

深拷贝

 string的遍历

重载 [] 下标访问

迭代器访问

reserve

resize

 增删查改

push_back()

append和+=

 insert和erase

find

substr

swap 

 流插入和流提取

getline

string其他基本功能


⭐了解string类

1. 字符串是表示字符序列的类
2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
3. string 类是使用 char( 即作为它的字符类型,使用它的默认 char_traits 和分配器类型 ( 关于模板的更多信息,请参阅basic_string)
4. string 类是 basic_string 模板类的一个实例,它使用 char 来实例化 basic_string 模板类,并用 char_traits和allocator 作为 basic_string 的默认参数 ( 根于更多的模板信息请参考 basic_string)
5. 注意,这个类独立于所使用的编码来处理字节 : 如果用来处理多字节或变长字符 ( UTF-8) 的序列,这个类的所有成员( 如长度或大小 ) 以及它的迭代器,将仍然按照字节 ( 而不是实际编码的字符 ) 来操作。
总结:
1. string 是表示字符串的字符串类
2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作 string 的常规操作。
3. string 在底层实际是: basic_string 模板类的别名, typedef basic_string<char, char_traits, allocator>
string;
4. 不能操作多字节或者变长字符的序列。
使用 string 类时,必须包含 #include 头文件以及 using namespace std ;

⭐string的内存管理

✨VS下string的结构

string总共占28个字节 ,内部结构稍微复杂一点,先是 有一个联合体,联合体用来定义 string 中字
符串的存储空间
  • 当字符串长度小于16时,使用内部固定的字符数组来存放
  • 当字符串长度大于等于16时,从堆上开辟空间
  1. union _Bxty
  2. { // storage for small buffer or pointer to larger one
  3. value_type _Buf[_BUF_SIZE];
  4. pointer _Ptr;
  5. char _Alias[_BUF_SIZE]; // to permit aliasing
  6. } _Bx;
  1. 大多数情况下字符串的长度都小于16,当string对象创建好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。
  2. 还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量
  3. 有一个指针做一些其他事情。
  4. 故总共占16+4+4+4=28个字节。

✨g++下string的结构

g++ 下, string 是通过写时拷贝实现的, string对象总共占4个字节 ,内部只包含了一个指针,该指
针将来指向一块堆空间,内部包含了如下字段:
  • 空间总大小
  • 字符串有效长度
  • 引用计数
  • 指向堆空间的指针,用来存储字符串。
  1. struct _Rep_base
  2. {
  3. size_type _M_length;
  4. size_type _M_capacity;
  5. _Atomic_word _M_refcount;
  6. };

 ⭐string的模拟实现

  1. private:
  2. char* _str = nullptr;
  3. size_t _size = 0;
  4. size_t _capacity = 0;

✨string的构造函数

  1. // 为了和标准库区分,此处使用String
  2. class String
  3. {
  4. public:
  5. /*String()
  6. :_str(new char[1])
  7. {*_str = '\0';}
  8. */
  9. //String(const char* str = "\0") 错误示范
  10. //String(const char* str = nullptr) 错误示范
  11. String(const char* str = "")//默认包含 \0
  12. {
  13. // 构造String类对象时,如果传递nullptr指针,可以认为程序非法
  14. if (nullptr == str)
  15. {
  16. assert(false);
  17. return;
  18. }
  19. _str = new char[strlen(str) + 1];
  20. strcpy(_str, str);
  21. }
  22. ~String()
  23. {
  24. if (_str)
  25. {
  26. delete[] _str;
  27. _str = nullptr;
  28. }
  29. }
  30. private:
  31. char* _str;
  32. };
  33. // 测试
  34. void TestString()
  35. {
  36. String s1("hello bit!!!");
  37. String s2(s1);
  38. }

 

上述 String 类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用 s1 s2 时,编译器会调用默认的拷贝构造。最终导致的问题是, s1 s2 共用同一块内存空间,在释放时同一块 空间被释放多次而引起程序崩溃 ,这种拷贝方式,称为 浅拷贝

 
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/706148

推荐阅读
相关标签