c++|【C++篇】STL常见容器String的模拟实现

准备 博主:大大怪先森(记得关注哦!)
编程环境:vs2013
所示代码:码源


文章目录

  • 准备
  • 前言
  • 一、标准库中的tring类
    • 1.了解类
    • 2.string类的常见接口
      • 2.1 string类对象的构造
      • 2.2 string类容器的操作
  • 二、String类的模拟实现
    • 1.深浅拷贝
    • 2.1.1浅拷贝
    • 2.1.2深拷贝
    • 2.写时拷贝
    • 3.String实现代码
  • 总结
  • 结语

前言
本章讲解String容器的相关知识!!!
提示:以下是本篇文章正文内容
一、标准库中的tring类 1.了解类
  1. string是表示字符串的字符串类
    2.该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作.
  2. string在底层实际是:basic_string模板类的别名,typedef basic_stringstring;
  3. 不能操作多字节或者变长字符的序列。
    注意:在使用string类时,必须包含#include头文件以及using namespace std;
2.string类的常见接口 2.1 string类对象的构造
(constructor)函数名称 功能说明
string() (重点) 构造空的string类对象,即空字符串
string(const char* s) (重点) 用C-string来构造string类对象
string(size_t n, char c) string类对象中包含n个字符c
string(const string&s) (重点) 拷贝构造函数
2.2 string类容器的操作
函数名称 功能说明
size(重点) 返回字符串有效字符长度
reserve (重点) 为字符串预留空间**
resize (重点) 将有效字符的个数该成n个,多出的空间用字符c填充
operator[] (重点) 返回pos位置的字符,const string类对象调用
begin+ end begin获取第一个一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
rbegin + rend 反向迭代器begin/end的用法相反,rfind获得最后一个字符的迭代器,rend获得第一个字符的迭代器
push_back 在字符串后尾插字符c
append 在字符串后追加一个字符串
operator+= (重点) 在字符串后追加字符串str
c_str(重点) 返回C格式字符串
find + npos(重点) 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr 在str中从pos位置开始,截取n个字符,然后将其返回
getline (重点) 获取一行字符串
iinsert 头插字符
二、String类的模拟实现 1.深浅拷贝 2.1.1浅拷贝
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以 当继续对资源进项操作时,就会发生发生了访问违规。
c++|【C++篇】STL常见容器String的模拟实现
文章图片

2.1.2深拷贝
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供
c++|【C++篇】STL常见容器String的模拟实现
文章图片

深拷贝为每一个对象开辟一个空间不会出现多处析构同一块空间的现象
2.写时拷贝
【c++|【C++篇】STL常见容器String的模拟实现】写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。
引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。
简单来说就是只有在你真正需要这块空间的时候才会给你开辟这一块空间,而在不需要的时候用户以为编译器给你了,但是编译器并没有在内存中为你开辟这一块空间。
3.String实现代码 代码如下(示例):
#pragma once #include #include #include #include #include #include using namespace std; //string类模拟增删查改的全部实现 namespace wzd { class string { public: typedef char* iterator; typedef const char* const_iterator; const_iterator begin()const { return _str; } const_iterator end()const { return _str + _size; } iterator begin() { return _str; } iterator end() { return _str + _size; } string(const char* str = "") :_size(strlen(str)) , _capacity(_size) { _str = new char[_capacity + 1]; strcpy(_str, str); } //传统写法 -- 本本分分去完成深拷贝 //s2(s1) /* string(const string& s) :_size(s._size) , _capacity(s._capacity) { _str = new char[_capacity + 1]; strcpy(_str, s._str); }*/ //现代写法:灵活运用构造函数 string(const string& s) :_str(nullptr) ,_size(0) , _capacity(0) { string tmp(s._str); swap(_str, tmp._str); } //传统写法:赋值函数的重载 /*string& opertor = (const string& s) { if (this != &s) { char* tmp = new char[s.capacity + 1]; strcpy(tmp, s._str); delete[] _str; _str = tmp; _size = s._size; _capacity = s.capacity; } retunrn *this; }*/ //现代写法:利用拷贝构造函数 /*string& opertor = (const string& s) { if (this != &s) { string tmp(s); swap(_str, tmp._str); } }*/ //现代写法更简单的一种方法:传参的时候实现拷贝构造 string& operator=(string s) { swap(_str, s._str); return *this; } ~string() { delete[] _str; _str = nullptr; _size = _capacity = 0; } const char* c_str()const { return _str; } size_t size()const { return _size; } char& operator[](size_t pos) { assert(pos < _size); retunr _str[pos]; } const char& operator[](size_t pos)const { assert(pos < _size); retunr _str[pos]; } void reserve(size_t n) { if (n > _capacity) { char* tmp = new char[n + 1]; strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } } void resize(size_t n, char ch = '\0') { if (n <= _size) { _size = n; _str[_size] = '\0'; } else { if (n > _capacity) { reverse(n); } memset(_str + _size, ch, n - _size); _size = n; _str[_size] = '\0'; } } void Push_back(char ch) { //if (_size == _capacity) //{ // //自己写的,代码有点小菜,为啥不想办法把空间交换 // //菜鸡 // /*char* tmp = new char[_capacity + 1]; // strcpy(tmp._str, _str) // _capacity = _capacity * 2; // _str = new char[_capacity + 1]; // strcpy(_str,tmp.str) // delete[] tmp; */ // reserve(_capacity == 0 ? 4 : _capacity * 2); //} //_str[_size] = ch; //++_size; //_str[_size] = '\0'; insert(_size, ch); } void append(const char* str) { /*if (_size + strlen(str) > _capacity) { reverse(_size + strlen(str)); } strcpy(_str + _size, str); _size = _size + strlen(str); */ insert(_size, str); } string& opeator += (char ch) { Push_back(ch); return *this; } string& opeator += (char ch)const { Push_back(ch); return *this; } size_t find(char ch) { for (size_t = 0; i < _size; i++) { if (ch == _str[i]) { return i; } } return npos; } size_t find(const char* s, size_t pos = 0) { const char* ptr = strstr(_str + pos, s); if (ptr == nullptr) { return npos; } else { return ptr - _str; } } string& insert(size_t pos, char ch) { assert(pos <= _size); if (_size == _capacity) { reserve(_capacity == 0 ? 4 : _capacity * 2); } //头插第一个位置的时候出现问题 //end - 1是-1的无符号整形中很大 //越界访问 /*size_t end = _size; while (end >= pos) { _str[end + 1] = _str[end]; --end; //pos是o这个地方end--是-1无穷大完蛋了!!! }*/ /*int end = _size; while (end >= (int)pos) { _str[end + 1] = _str[end]; --end; }*/ size end = _size + 1; while (end > pos) { _str[end] = _str[end - 1]; --end; } _str[pos] = ch; ++_size; return *this; } string& insert(size_t pos, const char* s) { assert(pos <= _size); size_t len = strlen(s); if (_size + len > _capacity) { reverse(_size + len); } size_t end = _size + len; whill(end > pos) { _str[end] = _str[end - len]; --end; } strncpy(_str + pos, s, len); return *this; } string& erase(size_t pos = 0, size_t len = npos) { assert(pos < _size); if (len == npos || pos + len >= _size) { _str[pos] = '\0'; _size = pos; } else { strcp(_str + pos, _str + pos + len); _size -= len; } return *this; } private: char* _str; size_t _size; size_t _capacity; static const int npos; }; } wzd::string::npos = -1;

总结
String作为c++语言中一个非常常见的容器,无论我们在刷题还是写项目的过程中一定会经常使用String这个容器,各位大大一定要能够熟练的掌握哦!!
其中还有许多String类中库函数这里没有讲解,各位可以参考cpulspuls这个官方的网站哦
结语
希望本篇文章能给各位带来帮助,如有不足还请指正!!! 码字不易,各位大大给个收藏点赞吧!!!

各位大大记得点赞,关注,一键三连哦!!!

    推荐阅读