STL-string类的使用及其模拟实现
string类的使用
string 类是 C++ 标准库提供的用于处理字符串的类,它相比 C 语言中的字符串处理函数更为高级、灵活和安全。
string 类提供了丰富的成员函数和操作符,用于处理字符串的拼接、查找、替换、截取、插入等操作。string 类自动处理字符串的内存分配和释放,不会像 C 语言中的字符数组那样容易出现缓冲区溢出等安全问题。使用 string 类能够有效避免许多与字符数组相关的安全漏洞。string 类是 C++ 标准模板库(STL)中的一部分,学习 string 类也是为了更好地理解和使用 STL 的其他组件,如向量、链表、映射等。
string类对象的常见构造:
string类对象的容量接口:
string类对象的元素访问:
string类对象的Iterators(迭代器)接口:
string类对象的修改:
npos
npos 是 std::string 类中的一个静态常量成员,用于表示无效或未找到的位置。它是一个特殊的 std::string::size_type 类型的常量,通常被定义为 std::string::npos,其值在不同的编译器和实现中可能不同,但通常被设为 -1 或一个非常大的值,用于表示在字符串中未找到指定的子串或字符。
npos 主要用于字符串查找操作,比如在使用 find()、rfind()等成员函数时,当查找失败或没有找到指定的子串或字符时,这些函数通常会返回 std::string::npos 来表示无效的位置。
注意:npos 的值是一个非常大的无符号整数,因此在比较 std::string::size_type 类型的值时,应使用无符号类型的比较方式,避免可能出现的错误。比如使用 pos != std::string::npos 来判断是否找到了指定的子串或字符。
string类的模拟实现
std::string 是一个类模板,模拟实现它需要深入理解类和对象的概念,包括构造函数、析构函数、成员函数、成员变量等。通过实现一个类似 std::string 的类,你可以更好地理解类的设计和使用。
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
iterator end() {
return _str + _size;
}
iterator begin() const
{
return _str;
}
iterator end() const{
return _str + _size;
}
/*string()
:_str(new char[1])
,_size(0)
,_capacity(0)
{
_str[0] = '\0';
}*/
string(const char* str = "")
:_size(strlen(str))//不包括'\0'的大小
{
_capacity = _size==0 ? 3 : _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
string(const string& s)
:_size(s._size)
,_capacity(s._capacity)
{
_str = new char[s._capacity+1];
strcpy(_str, s._str);
}
// 传统写法
string& operator=(const string& s) {
if (this != &s) {
/*delete[] _str;
_str = new char[s._capacity + 1];
strcpy(_str, s._str);
_size = s._size;
_capacity = s._capacity;
return *this;*/
char* tmp = new char[s._capacity + 1];
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;
}
}
// 现代写法
void swap(string& tmp)
{
::swap(_str, tmp._str);
::swap(_size, tmp._size);
::swap(_capacity, tmp._capacity);
}
string(const string& s)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
string tmp(s._str);
swap(tmp);
}
~string() {
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
string to_string(int value)
{
bool flag = true;
if (value < 0)
{
flag = false;
value = 0 - value;
}
string str;
while (value > 0)
{
int x = value % 10;
value /= 10;
str += ('0' + x);
}
if (flag == false)
{
str += '-';
}
std::reverse(str.begin(), str.end());
return str;
}
const char* c_str() {
return _str;
}
const char& operator[](size_t pos) const {
assert(pos < _size);
return _str[pos];
}
char& operator[](size_t pos) {
assert(pos < _size);
return _str[pos];
}
size_t size() const{
return _size;
}
size_t capacity() const {
return _capacity;
}
//string& operator=(const string& s)
//{
// if (this != &s)
// {
// //string tmp(s._str);
// string tmp(s);
// swap(tmp); // this->swap(tmp);
// }
// return *this;
//}
string& operator=(const string& s)
{
if (this != &s) //防止自己给自己赋值
{
string tmp(s); //用s拷贝构造出对象tmp
swap(tmp); //交换这两个对象
}
return *this; //返回左值(支持连续赋值)
}
//不修改成员变量数据的函数,最好都加上const
bool operator>(const string& s) const {
return strcmp(_str, s._str) > 0;
}
bool operator==(const string& s) const {
return strcmp(_str, s._str) == 0;
}
bool operator>=(const string& s) const {
return *this > s || *this == s;
}
bool operator<(const string& s) const {
//return strcmp(_str, s._str) < 0;
return !(*this >= s);
}
bool operator<=(const string& s) const {
//return *this < s || *this == s;
return !(*this > s);
}
//扩容
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) {
//删除数据--保留前n个
_size = n;
_str[_size] = '\0';
}
else {
if (n > _capacity) {
reserve(n);
}
size_t i = _size;
while (i < n) {
_str[i] = ch;
++i;
}
_size = n;
_str[_size] = '\0';
}
}
void push_back(char ch) {
/*if (_size + 1 > _capacity) {
reserve(_capacity * 2);
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';*/
insert(_size, ch);
}
void append(const char* str) {
//size_t len = strlen(str);
//if (_size + len > _capacity) {
// reserve(_size + len);
//}
//strcpy(_str + _size, str);
strcat(_str,str);
//_size += len;
insert(_size, str);
}
string& operator+=(char ch) {
push_back(ch);
return *this;
}
string& operator+=(const char* str) {
append(str);
return *this;
}
string& insert(size_t pos, char ch) {
assert(pos <= _size);
if (_size + 1 > _capacity) {
reserve(2 * _capacity);
}
//int end = _size;
//while (end >= (int)pos) {//有符号跟无符号类型比较会发生整型提升变成无符号类型
// _str[end + 1] = _str[end];
// --end;
//}
size_t 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* str) {
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity) {
reserve(_size + len);
}
//挪动数据
size_t end = _size + len;
while (end > pos+len-1) {
_str[end] = _str[end - len];
--end;
}
/*size_t end = _size;
for (size_t i = 0; i < _size + 1; ++i) {
_str[end] = _str[end - len];
--end;
}*/
//拷贝插入
strncpy(_str + pos, str, len);
_size += len;
return *this;
}
string& erase(size_t pos, size_t len = npos) {
assert(pos < _size);
if (len == npos || pos + len >= _size) {
_str[pos] = '\0';
_size = pos;
}
else {
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
return *this;
}
//swap(s1,s2);
//s1.swap(s2);比上面更高效
void swap(string& s) {
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
size_t find(char ch,size_t pos=0) {
assert(pos < _size);
for (size_t i = pos; i < _size; ++i) {
if (_str[i] == ch) {
return i;
}
}
return npos;
}
size_t find(const char* str, size_t pos = 0) {
assert(pos < _size);
char* p = strstr(_str + pos, str);
if (p == nullptr) {
return npos;
}
else {
return p - str;
}
}
void clear() {
_str[0] = '\0';
_size = 0;
}
private:
char* _str;
size_t _size;
size_t _capacity;
//static const size_t npos;
static const size_t npos = -1;
//static const double npos = -1.0;//错误,只针对整型
};
//const size_t string::npos = -1;
ostream& operator<<(ostream& out, const string& s) {
for (auto ch : s) {
out << ch;
}
return out;
}
istream& operator>>(istream& in, string& s) {
s.clear();
char ch=in.get();
char buff[128];
size_t i = 0;
while (ch != ' ' && ch != '\n') {
buff[i++] = ch;
if (i == 127) {
buff[127] = '\0';
s += buff;
i = 0;
}
ch= in.get();
}
if (i !=0) {
buff[i] = '\0';
s += buff;
}
return in;
}
构造函数
//构造函数
/*string()
:_str(new char[1])
,_size(0)
,_capacity(0)
{
_str[0] = '\0';
}*/
//string(const char* str=nulltr)不可以,strlen检测不到'\0'会崩
//string(const char* str='\0')不可以,类型不匹配
//string(const char* str="\0")可以,但是C语言规定常量字符串后面会有默认'\0'会造成歧义
string(const char* str = "")
:_size(strlen(str))//不包括'\0'的大小
{
_capacity = _size==0 ? 3 : _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
构造函数我们可以用无参和带参的构造,但是最好的方式是全缺省,const char* str = “” 是构造函数的默认参数。
拷贝构造
浅拷贝:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间。其中一个对象的改动会对另一个对象造成影响。
深拷贝:深拷贝是指源对象与拷贝对象互相独立。其中任何一个对象的改动不会对另外一个对象造成影响。
因为我们并不希望源对象与拷贝对象存在关系,所以我们需要实例化出新的对象再进行拷贝。
传统写法:
string(const string& s)
:_size(s._size)
,_capacity(s._capacity)
{
_str = new char[s._capacity+1];
strcpy(_str, s._str);
}
现代写法:
void swap(string& s) {
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
string(const string& s)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
string tmp(s._str);
swap(tmp);
}
swap 函数的实现会交换当前对象和临时对象的内存空间资源,而临时对象会在析构时释放资源。
这种实现方式通过避免了不必要的内存拷贝,从而提高了拷贝构造函数的性能。
赋值运算符重载
传统写法:
string& operator=(const string& s) {
if (this != &s) {
/*delete[] _str;
_str = new char[s._capacity + 1];
strcpy(_str, s._str);
_size = s._size;
_capacity = s._capacity;
return *this;*/
char* tmp = new char[s._capacity + 1];
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;
}
}
现代写法:
//现代写法2
string& operator=(const string& s)
{
if (this != &s) //防止自己给自己赋值
{
string tmp(s); //用s拷贝构造出对象tmp
swap(tmp); //交换这两个对象
}
return *this; //返回左值(支持连续赋值)
}
析构函数
~string() {
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
扩容
void reserve(size_t n) {
if (n > _capacity) {
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
获取对应位置字符
const char& operator[](size_t pos) const {
assert(pos < _size);
return _str[pos];
}
char& operator[](size_t pos) {
assert(pos < _size);
return _str[pos];
}
改变字符串大小
void resize(size_t n, char ch = '\0') {
if (n <= _size) {
//删除数据--保留前n个
_size = n;
_str[_size] = '\0';
}
else {
if (n > _capacity) {
reserve(n);
}
size_t i = _size;
while (i < n) {
_str[i] = ch;
++i;
}
_size = n;
_str[_size] = '\0';
}
}
迭代器
iterator begin()
{
return _str;
}
iterator end() {
return _str + _size;
}
iterator begin() const
{
return _str;
}
iterator end() const{
return _str + _size;
}
数字转字符串
string to_string(int value)
{
bool flag = true;
if (value < 0)
{
flag = false;
value = 0 - value;
}
string str;
while (value > 0)
{
int x = value % 10;
value /= 10;
str += ('0' + x);
}
if (flag == false)
{
str += '-';
}
std::reverse(str.begin(), str.end());
return str;
}
字符/字符串任意位置插入
string& insert(size_t pos, char ch) {
assert(pos <= _size);
if (_size + 1 > _capacity) {
reserve(2 * _capacity);
}
//int end = _size;
//while (end >= (int)pos) {//有符号跟无符号类型比较会发生整型提升变成无符号类型
// _str[end + 1] = _str[end];
// --end;
//}
size_t 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* str) {
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity) {
reserve(_size + len);
}
//挪动数据
size_t end = _size + len;
while (end > pos+len-1) {
_str[end] = _str[end - len];
--end;
}
/*size_t end = _size;
for (size_t i = 0; i < _size + 1; ++i) {
_str[end] = _str[end - len];
--end;
}*/
//拷贝插入
strncpy(_str + pos, str, len);
_size += len;
return *this;
字符/字符串的追加
void push_back(char ch) {
/*if (_size + 1 > _capacity) {
reserve(_capacity * 2);
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';*/
insert(_size, ch);
}
void append(const char* str) {
//size_t len = strlen(str);
//if (_size + len > _capacity) {
// reserve(_size + len);
//}
//strcpy(_str + _size, str);
strcat(_str,str);
//_size += len;
insert(_size, str);
}
string& operator+=(char ch) {
push_back(ch);
return *this;
}
string& operator+=(const char* str) {
append(str);
return *this;
}
}
从任意位置删除n个字符
string& erase(size_t pos, size_t len = npos) {
assert(pos < _size);
if (len == npos || pos + len >= _size) {
_str[pos] = '\0';
_size = pos;
}
else {
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
return *this;
}
查找字符/字符串
size_t find(char ch,size_t pos=0) {
assert(pos < _size);
for (size_t i = pos; i < _size; ++i) {
if (_str[i] == ch) {
return i;
}
}
return npos;
}
size_t find(const char* str, size_t pos = 0) {
assert(pos < _size);
char* p = strstr(_str + pos, str);
if (p == nullptr) {
return npos;
}
else {
return p - str;
}
}
将字符串置空
void clear() {
_str[0] = '\0';
_size = 0;
}
获取字符串
const char* c_str() {
return _str;
}
比较运算符重载
bool operator>(const string& s) const {
return strcmp(_str, s._str) > 0;
}
bool operator==(const string& s) const {
return strcmp(_str, s._str) == 0;
}
bool operator>=(const string& s) const {
return *this > s || *this == s;
}
bool operator<(const string& s) const {
//return strcmp(_str, s._str) < 0;
return !(*this >= s);
}
bool operator<=(const string& s) const {
//return *this < s || *this == s;
return !(*this > s);
}
流提取和流插入运算符重载
ostream& operator<<(ostream& out, const string& s) {
for (auto ch : s) {
out << ch;
}
return out;
}
istream& operator>>(istream& in, string& s) {
s.clear();
char ch=in.get();
char buff[128];
size_t i = 0;
while (ch != ' ' && ch != '\n') {
buff[i++] = ch;
if (i == 127) {
buff[127] = '\0';
s += buff;
i = 0;
}
ch= in.get();
}
if (i !=0) {
buff[i] = '\0';
s += buff;
}
return in;
}
原文地址:https://blog.csdn.net/m0_62975443/article/details/136608582
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!