1.1. C语言中的字符串处理 在C语言中,字符串都是以“\0”结尾的字符集合,为了操作这个字符集合,C语言提供了str系列的标准库,如:strlen、strcat、strcpy等。但是这些函数与字符串时分离的,也就是说,C语言中的字符串并不是以对象形式出现的,所以这就并不符合C++中的面向对象的思想,并且底层空间依然需要用户自己管理,而且可能出现越界访问的情况。 为了更加方便地使用字符串,C++设计了string类。
2.1. string类 string官方文档 在使用string类时,一定要包含#include<string>,这里注意区分string和string.h!!!
总结:


int main()
{
string s1; //构造空的s1 等价于string s1("");
string s2("hello");//用C格式字符串构造
string s3(s2); //调用拷贝构造函数
return 0;
}
接下来我们模拟实现一下string的构造函数。
class string
{
public:
//全缺省构造函数
string(const char* str = "")
: _size(strlen(str))
, _capacity(_size)
{
//实际上要多开一个 留给'\0'
_str = new char[_capacity + 1];
strcpy(_str, str);//会把'\0也拷过去'
}
private:
char* _str;
size_t _size;//有效字符数量,不包括"\0"
size_t _capacity;//
};这段代码还是比较简单的,就是要注意,strcpy会将字符串末尾“\0”也拷贝过去。
基本写法:
string(const string& s)
:_size(strlen(s._str))
,_capacity(_size)
{
_str = new char[_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);
}这里的基本写法不能理解,但是这个现代写法似乎有点抽象,我们在后面的赋值拷贝来进行讲解。
我们在写任何一个一个类型的赋值运算符重载类型的时候都要考虑下面这几个问题:

string& operator=(const string& s)结合上面四点我们写出下面的代码:
string& operator=(const string& s)
{
if (this == &s)
return *this;//自己赋值自己 直接返回
delete[] _str;
_str = nullptr;
_str = new char[strlen(s._str) + 1];
strcpy(_str, s._str);
return *this;
}这个代码已经能够解决我们上面提到的问题了,但是我们考虑一种更加极端的安全情况,那就是,如果在delete[ ] _str之后,系统没有足够的空间来new char[ ],那么此时就会抛出异常,那么此时_str就会处于既不是nullptr,也没有保持原来状态,这就违背了异常安全原则。
有两种方法来解决这个安全问题:
string& operator=(const string& s)
{
if (this != &s)
{
string tmp(s._str);
std::swap(_str, tmp._str);
std::swap(_size, tmp._size);
std::swap(_capacity, tmp._capacity);
}
return *this;
}然后我们来看看我们模拟string的效果:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
namespace s
{
class string
{
public:
//全缺省的构造函数
string(const char* str = "")
:_size(strlen(str))
, _capacity(_size)
{
//实际上要多开一个 留给'\0'
_str = new char[_capacity + 1];
strcpy(_str, str);//会把'\0也拷过去'
}
string(const string& s)
:_size(strlen(s._str))
, _capacity(_size)
{
_str = new char[_capacity + 1];
strcpy(_str, s._str);
}
//string& operator=(const string& s)
//{
// if (this == &s)
// return *this;//自己赋值自己 直接返回
// delete[] _str;
// _str = nullptr;
// _str = new char[strlen(s._str) + 1];
// strcpy(_str, s._str);
// return *this;
//}
string& operator=(const string& s)
{
if (this != &s)
{
string tmp(s._str);
std::swap(_str, tmp._str);
std::swap(_size, tmp._size);
std::swap(_capacity, tmp._capacity);
}
return *this;
}
~string()
{
if (_str)
{
delete[] _str;
_str = nullptr;
_size = 0;
_capacity = 0;
}
}
private:
char* _str;
size_t _size;//有效字符个数 不算'/0';
size_t _capacity;//实际存储有效字符的空间
};
}
int main()
{
s::string s1("Hello World");
s::string s2;
s::string s3;
/*std::string s1("Hello World");
std::string s2;
std::string s3;*/
s3 = s2 = s1;
return 0;
}赋值前:

赋值后:

(本篇完)