c++STL之string类

本文深入探讨了C++中String类的构造、容量操作、访问与遍历、修改方法等核心功能,解析了深拷贝与浅拷贝的区别,以及String类的模拟实现。

1.为何要学习string类
符合面向对象的思想,而且底层空间不需要用户自行控制,不会发生越界访问的情况
2.string类的接口
2.1string类对象的常见构造

函数名称 功能说明
string() 构造空的string类对象,即空字符串
string(const char*s) 用C-string来构造string类对象
string(size_t n,char c) string类对象包含n个字符cstring(const string&s) 拷贝构造函数

void Test(){    
string s1;    
string s2("hello");    
string s3(s2);
}

2.2string类对象的容量操作

函数名称 功能说明
size 返回字符串有效字符长度
length 返回字符串有效字符长度
capacity 返回空间总大小
empty 检测字符串是否为空串,是返回true,否则返回false
clear 清空有效字符
reserve 扩大容量
resize 将有效元素个数扩大到n个,多出来的空间用字符c填充

//resize:将原有字符串扩增到n个//resize作用:改变string中有效字符的个数//将有效字符增多到n个,多出的位置需要使用ch进行填充,可能需要扩容//将有效字符减少到n个,只修改有效字符的个数,不会缩小空间
int main() {       
string s1("hello");       
for (auto e : s1) {              
cout << e;       
}       
cout << endl;       
cout << s1.size()<<endl;       
cout << s1.capacity()<<endl;       
s1.resize(10, '!');       
for (auto e : s1) {              
cout << e;       
}       
cout << endl;       
cout << s1.size() << endl;       
cout << s1.capacity()<<endl;       
s1.resize(80, '!');       
cout << s1.size() << endl;       
cout << s1.capacity()<<endl;       
s1.resize(1);       
for (auto e : s1) {              
cout << e;       
}       
cout << endl;       
cout << s1.size() << endl;       
cout << s1.capacity() << endl;       
system("pause");       
return 0;
}
//reserve:改变底层容量的大小,有效元素个数不会变
//扩大容量:n<=旧空间大小,不会扩容  n>旧空间大小,扩容
//缩小容量:n>15 不会缩小  n<=15 缩小容量
int main() {       
string s1("hello");       
cout << s1.size() << endl;       
cout << s1.capacity() << endl;       
s1.reserve(10);       
cout << s1.size() << endl;       
cout << s1.capacity() << endl;       
s1.reserve(60);       
cout << s1.size() << endl;       
cout << s1.capacity() << endl;       
s1.reserve(30);       
cout << s1.size() << endl;       
cout << s1.capacity() << endl;       
s1.reserve(6);      
cout << s1.size() << endl;       
cout << s1.capacity() << endl;       
system("pause");       
return 0;
}

注意:
1).clear()只是将string中有效字符清空,不改变底层空间的大小2).resize在啊改变元素个数时,如果将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变3).reserve为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间大小时,reserve不会改变容量大小

2.3string类对象的访问及遍历操作
string类的三种遍历方式

int main() {       
string s1;       
string s2("hello");       
string s3(10, '$');       
string s4(s3);       
cin >> s1;       
cout << s1 << endl;       
cout << s1.size() << endl;       
cout << s1.capacity() << endl;       
//范围for遍历       
for (auto e : s2) {              
cout << e;       }       
cout << endl;       
cout << s2.size()<<endl;       
cout << s2.capacity() << endl;       
//下标遍历       
for (size_t i = 0;i < s3.size();i++) {              
cout << s3[i];       
}       
cout << endl;       
cout << s3.size() << endl;       
cout << s3.capacity() << endl;       
//迭代器遍历       
//string::iterator it = s4.begin();c++98       
auto it = s4.begin();//c++11       
while (it != s4.end()) {              
cout << *it;              
it++;       
}       
cout << endl;       
cout << s4.size() << endl;       
cout << s4.capacity() << endl;       
s4.clear();       
cout << s4.size() << endl;       
cout << s4.capacity() << endl;       
system("pause");       
return 0;
}

string类的访问

char& operator[](size_t index) {              
assert(index < _size);              
return _str[index];       
}       
const char& operator[](size_t index)const {              assert(index < _size);              
return _str[index];       
}       
int main(){           
 string s1("hello");           
 s1[0]='a';           
return 0;             
}

2.4string 类对象的修改操作

函数名称 功能说明
push_back 在字符串后尾插字符c
append 在字符串后支架一个字符串
operator+= 在字符串后追加字符串
strc_str 返回c格式的字符串
find 从字符串pos位置开始往后找字符c,返回该字符在字 符串中的位置
rfind 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr 在str中从pos位置开始,截取n个字符,然后将其返回

int main() {       
string s1("asdfghj.jk.txt");       cout<<s1.substr(s1.rfind('.')+1)<<endl;       
system("pause");       
return 0;
}

string s1("hello");      
cout << s1 << endl;       
reverse(s1.begin(), s1.end());       
cout << s1 << endl;       
string s2("world");       
s1 += ' ';       
s1 += s2;       
s1 += "!!";       
cout << s1 << endl;       
s1.append("very", 3);       
cout << s1 << endl;       
s1.append(s2, 2, 2);       
cout << s1 << endl;       
s1.push_back('.');       
cout << s1 << endl;       
system("pause");       
return 0;
}

注意:
1)在string尾部追加字符时,s.push_back©/s.append(1,c)/s+='c’三中实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以链接单个字符,还可以链接字符串
2)对string操作时,如果大概能预估到放多少字符,可以先通过reserve把空间预留好

3.string类的模拟实现
3.1 浅拷贝浅拷贝也称位拷贝,编译器只是将对象中的值拷贝过来,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进行操作时,就会发生访问违规

int main(){
string s1("hello");
string s2(s1);//未自主定义拷贝构造函数,编译器会默认生成一个拷贝构造函数,即浅拷贝
return 0;
}

浅拷贝解决方式:采用深拷贝

3.2 深拷贝深拷贝:给每个对象独立分配资源,保证多个对象之间不会因共享资源而造成多次释放造成程序崩溃问题
如果一个类中涉及到资源的管理,其拷贝构造函数,赋值运算符重载以及析构函数必须显示给出,一般情况都是按照深拷贝的方式提供

3.2.1传统版写法的string类以及现代版写法的string类

class string {
public:
string(const char* str = " ") {
if (str == nullptr) {
   str = " ";
}
  _str = new char[strlen(str) + 1];
strcpy(_str, str);
}
//传统版
//string(const string& s)
// :_str(new char[strlen(s._str) + 1])
//{
// strcpy(_str, s._str);
//}
//string& operator=(const string& s) {
// if (this != &s) {
//  char*str = new char[strlen(s._str) + 1];
//  strcpy(str, s._str);
//  delete[]_str;
//  _str = str;
// }
// return *this;
//}
//简介版--现代版
string(const string& s)
:_str(nullptr)
{
  string strTemp(s._str);
swap(_str, strTemp._str);
}
 string& operator=(string s) {
swap(_str, s._str);
return *this;
}
~string() {
if (_str) {
   delete[]_str;
   _str = nullptr;
}
}
private:
char* _str;
};
int main() {
 std::string s1;
 std::string s2("hello");
//系统提供的默认拷贝构造函数: 会造成浅拷贝
 std::string s3(s2);
//系统提供的默认赋值运算符重载:1.浅拷贝 2.资源泄露
 std::string s4("world");
 s4 = s3;
return 0;
}

3.3写时拷贝

class string {
public:
string(const char* str = " ") {
if (str == nullptr) {
   str = " ";
}
  _str = new char[strlen(str) + 1];
strcpy(_str, str);
  _pCount = new int(1);
}
string(const string& s)
:_str(s._str)
,_pCount(s._pCount)
{
++(*_pCount);
}
 string& operator=(const string& s) {
if (this != &s) {
if (0 == -- * _pCount) {
    delete[]_str;
    delete[]_pCount;
}
   _str = s._str;
   _pCount = s._pCount;
++* _pCount;
}
return *this;
}
~string() {
if (_str&&0==--*_pCount) {
   delete[]_str;
   _str = nullptr;
   delete _pCount;
   _pCount = nullptr;
}
}
private:
char* _str;
int* _pCount;
};
int main() {
 std::string s1;
 std::string s2("hello");
 std::string s3(s2);
return 0;
}

模拟实现string类

#include<assert.h>
class string {
public:
 typedef char* iterator;
public:
 string(const char* str = " ") {
  if (str == nullptr) {
   str = " ";
  }
  _size = strlen(str);
  _str = new char[_size+ 1];
  strcpy(_str, str);
  _capacity = _size;
 }
 string(size_t n, char ch)
  :_str(new char[n + 1])
  , _size(n)
  , _capacity(n)
 {
  memset(_str, ch, _size);
  _str[_size] = '\0';
 }
 string(const string& s)
  :_size(s._size)
  , _capacity(s._size)
 {
  _str = new char[_size + 1];
  strcpy(_str, s._str);
 }
 string& operator=(const string& s) {
  if (this != &s) {
   char* str = new char[s._size + 1];
   strcpy(str, s._str);
   delete[]_str;
   _str = str;
   _size = s._size;
   _capacity = _size;
  }
  return *this;
 }
 ~string() {
  if (_str) {
   delete[]_str;
   _str = nullptr;
  }
 }
 char& operator[](size_t index) {
  assert(index < _size);
  return _str[index];
 }
 const char& operator[](size_t index)const {
  assert(index < _size);
  return _str[index];
 }
 size_t size()const {
  return _size;
 }
 size_t capacity()const {
  return _capacity;
 }
 void resize(size_t newsize, char ch=char()) {
  size_t oldsize = _size;
 if(newsize>oldsize) {
   if (newsize > _capacity) {
    reserve(_capacity);
   }
   memset(_str + _size, ch, newsize - oldsize);
  }
  _size = newsize;
  _str[_size] = '\0';
 }
 void reserve(size_t newcapacity) {
  if (newcapacity > _capacity) {
   char* str = new char[newcapacity + 1];
   strcpy(str, _str);
   delete[]_str;
   _str = str;
   _capacity = newcapacity;
  }
 }
 string& operator+=(char ch) {
  if (_size = _capacity) {
   reserve(2 * _capacity);
  }
  _str[_size++] = ch;
  _str[_size] = '\0';
  return *this;
 }
 string& operator+=(char* str) {
  size_t len = strlen(str);
  size_t newsize = size() + len;
  if (capacity() < newsize) {
   reserve(newsize);
  }
  strcat(_str, str);
  _size = newsize;
  return *this;
 }
 string& operator+=(const string& s) {
  *this += s._str;
  return *this;
 }
 void swap(string& s) {
  std::swap(_str, s._str);
  std::swap(_size, s._size);
  std::swap(_capacity, s._capacity);
 }
 const char* c_str()const {
  return _str;
 }
 size_t find(char ch) {
  for (size_t i = 0;i < size();i++) {
   if (_str[i] == ch) {
    return i;
   }
  }
  return -1;
 }
 iterator begin() {
  return _str;
 }
 iterator end() {
  return _str + _size;
 }
private:
 char* _str;
 size_t _capacity;
 size_t _size;
};
int main() {
 std::string s1;
 std::string s2("hello");
 std::string s3(10, '!');
 std::string s4(s2);
 s3 = s4;
 s4[0] = 'a';
 s4.swap(s2);
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值