??? ?目录
一、整体结构
二、普通构造
三、析构函数
四、拷贝构造
? 1.深拷贝与浅拷贝
2.写法一
3.写法二
五、赋值
1.写法一
2.写法二
一、整体结构
? ? ? ? 本文只简单实现string函数的构造、析构、赋值,因此成员变量只需要一个字符指针。如果要完整的实现string类,还需要设置成员变量size、capacity。
class string
{
public:
string(const char* str = "");
string(const string& s);
string& operator=(const string& s);
~string();
private:
char* _str;
//size_t _size;
//size_t _capacity;
};
二、普通构造
? ? ? ? 参数为const修饰的字符指针,设置默认值为空字符串,这样可以用strlen来计算长度。申请完空间后,将参数的字符串拷贝到类实例的_str中。
string(const char* str = "")
:_str(new char[strlen(str) + 1])
{
strcpy(_str, str);
}
三、析构函数
? ? ? ? string类型变量生命周期结束后,析构函数对变量中创建的空间进行释放。
~string()
{
delete[] _str;
_str == nullptr;
}
四、拷贝构造
? 1.深拷贝与浅拷贝
? ? ? ?如果是下面的写法,将传进来的参数中的_str内容复制给实例的_str。这样就相当与让新的实例的字符指针指向参数的字符内容。两个实例的字符指针指向同一块空间,这样就叫做浅拷贝。在string类中析构函数会对_str释放空间,这时当一个指针释放完这块空间后,另一个指针再次释放就会导致出错。
string(const string& s)
:_str(s._str)
{}
? ? ? ? ?因此要完成string的拷贝构造,必须要使用深拷贝。开辟一个新的空间,再把字符串内容拷贝下来。这样他们各自调用析构函数释放空间就不会影响.
?
2.写法一
? ? ? ? 比较规矩的写法,先开好新的空间,再对字符串内容拷贝。
string(const string& s)
:_str(new char[strlen(s._str)+1])
{
strcpy(_str, s._str);
}
3.写法二
? ? ? ? 取巧的方法,复用上述的普通构造出一个临时变量,再将临时变量的字符指针与要当前字符指针一交换就完成了。临时变量销毁调用析构函数释放的是原来_str指向的空间,新的空间已经创建并拷贝好,由当前实例的析构来释放。
string(const string& s)
:_str(nullptr)
{
string temp(s._str);
std::swap(_str,temp._str);
}
五、赋值
1.写法一
? ? ? ? 常规写法,先释放原来的空间,再创建好空间进行拷贝。需要注意的是要进行判断是否是自己给自己本身赋值的情况,如s1=s1。否则在这种情况下这样的写法无法完成赋值。
string& operator=(const string& s)
{
if (this != &s)
{
char* temp = new char[strlen(s._str) + 1];
delete[] _str;
_str = temp;
strcpy(_str, s._str);
}
return *this;
}
2.写法二
? ? ? ? 这种写法利用了参数中的拷贝构造,交换两个字符指针指向的空间,使当前实例的字符指针指向了已经拷贝好的字符串空间。同时也不需要考虑本身赋值和空间释放的问题。
string& operator=(string s)
:_str(nullptr)
{
swap(s._str,_str)
return *this;
}
|