【C++】C++STL 揭秘:Strng背后的底层逻辑(一)https://developer.aliyun.com/article/1617335
十三、push_back
void push_back(char ch) { // 扩容2倍 if (_size == _capacity) { reserve(_capacity == 0 ? 4 : 2 * _capacity); } _str[_size] = ch; ++_size; _str[_size] = '\0'; //insert(_size, ch); }
说明:
- 插入单个字符时,需要判断空间是否充足
- 跟顺序表的尾插差不多
- 实现任意位置插入,直接内部调用insert也是可以的
十四、append
void append(const char* str) { // 扩容 size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } strcpy(_str + _size, str);//在尾部拷贝完成添加操作 _size += len; //insert(_size, str); }
说明:
- 当然可以选择一开始直接扩容
- 插入字符串时,需要判断空间是否充足
- 跟顺序表的尾插差不多
- 实现任意位置插入,直接内部调用insert也是可以的
十五、operator +=
string& operator+=(char ch) { push_back(ch); return *this; } string& operator+=(const char* str) { append(str); return *this; }
十六、find
16.1 寻找字符
size_t find(char ch, size_t pos = 0) const { assert(pos < _size); for (size_t i = pos; i < _size; i++) { if (_str[i] == ch) return i; } return npos; }
说明:
- 从任意位置遍历,找到返回该位置索引
- 没有找到就返回npos(-1)
- const修饰函数,仅限于读权限
16.2 寻找字符串
size_t find(const char* sub, size_t pos = 0) const { assert(pos < _size); const char* p = strstr(_str + pos, sub); if (p) { return p - _str; } else { return npos; } }
说明:
- strstr匹配所需字符串,返回匹配到字符串第一个位置
- 如果为空,表示不存在
- 如果找到了,利用指针-指针,得到下标位置索引
十七、substr
string substr(size_t pos = 0, size_t len = npos) { string sub; //if (len == npos || len >= _size-pos) if (len >= _size - pos) { for (size_t i = pos; i < _size; i++) { sub += _str[i]; } } else { for (size_t i = pos; i < pos + len; i++) { sub += _str[i]; } } return sub; }
说明:
- substr功能是返回从指定位置开始len长度的字符串
- 先创建string空对象用于接收截取字符串
- 当
len == npos
或len >= _size - pos
,代表了从pos位置到尾的字符串截取。- 尽量书写
len >= _size - pos
,而不是len + pos >= _size
这种,是为了防止len + pos
超过类型最大值范围
十八、clear
void clear() { _size = 0; _str[_size] = '\0'; }
清空资源,不释放空间
十九、erase
void erase(size_t pos = 0, size_t len = npos) { assert(pos <= _size); if (pos > _size - len || len==npos) { _str[pos] = '\0'; _size = pos; } else { strcpy(_str + pos, _str + pos + len); _size -= len; } }
具体说明:如果长度大于从指定位置到结束位置的长度,只需要在pos位置设置结束标识符。不然的话,就是将需要清空位置被后面的内容覆盖就行。如果对于strcpy这块逻辑不明白,可以回顾下strcpy使用方法。
二十、运算符重载
bool operator==(const string& s1, const string& s2) { int ret = strcmp(s1.c_str(), s2.c_str()); return ret == 0; } bool operator<(const string& s1, const string& s2) { int ret = strcmp(s1.c_str(), s2.c_str()); return ret < 0; } bool operator<=(const string& s1, const string& s2) { return s1 < s2 || s1 == s2; } bool operator>(const string& s1, const string& s2) { return !(s1 <= s2); } bool operator>=(const string& s1, const string& s2) { return !(s1 < s2); } bool operator!=(const string& s1, const string& s2) { return !(s1 == s2); }
说明:跟类和对象实现日期Date是一样的,具体有需要点击该连接日期类
二十一、实现迭代器
21.1 可读可修改
typedef char* iterator; iterator begin() { return _str; } iterator end() { return _str + _size; }
22.2 可读不可修改
typedef const char* iterator; const_iterator begin() const { return _str; } const_iterator end() const { return _str + _size; }
说明:
- 迭代器是一个像指针的东西,可以是指针,也可以不是指针,具体还需要看底层实现
- 这里使用指针实现迭代器,返回第一个位置和最后一个位置的下一个位置。
二十三、模拟实现流插入和流提取
23.1 operator<<(流插入)
#include<iostream> using namespace std; ostream& operator<<(ostream& out, const string& s) { for (auto ch : s) { out << ch; } return out; }
说明:
operator
是C++标准库中的一个类,用于输出数据流,位于标准命名空间std中。对此需要引用std命名空间访问。out << ch;
重载的<<
运算符用于将字符ch
写入输出流out
是C++标准库中重载
23.2 operator>>(流提取)
istream& operator>>(istream& in, string& s) { s.clear(); char ch; //in >> ch; ch = in.get(); char buff[128]; size_t i = 0; while (ch != ' ' && ch != '\n') { buff[i++] = ch; // [0,126] if (i == 127) { buff[127] = '\0'; s += buff; i = 0; } ch = in.get(); } if (i > 0) { buff[i] = '\0'; s += buff; } return in; }
具体流程:首先clear先清空对象中的资源,这里需要考虑char类型的最大值为128,创建个数组用于输入到类中,使用operator+=将得到的字符串输入到对象中。
流提取是将从键盘中读取的数据存储到s对象中,至于返回类型为istream&
是为支持连续流提取操作cin >> s >> s2
。string中getline接口模拟实现是一样的就不展开.
【C++】C++STL 揭秘:Strng背后的底层逻辑(三)https://developer.aliyun.com/article/1617337