c_str(cpp中使用了string,要和c语言兼容,用c去读文件等)
string模拟实现
构造函数+析构函数
注意:1.空对象初始化时开一个空间:\0
2.写全缺省,隐含了一个\0,只要是常量字符串,后面都已\0为结尾
/*string() //无参构造函数
:_str(new char[1])
,_size(0)
,_capacity(0)
{
_str[0] = '\0';
}*/
//string(const char* str = "")//strlen时间复杂度O(N)
// :_str(new char[strlen(str)+1])
// ,_size(strlen(str))
// , _capacity(strlen(str))//capacity不包含\0,只统计有效字符
//{
// strcpy(_str, str);
//}
string(const char* str = "")//全缺省,隐含了一个\0,只要是常量字符串,后面都已\0为结尾
{
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
~string()
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
拷贝构造函数:深拷贝
默认的拷贝构造,代码崩溃原因:浅拷贝指向同一块空间并析构两次(默认生成拷贝构造对内置类型值拷贝)
void test_string2()
{
string s1("hello world");
string s2(s1);
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
}
正确的普通写法
string(const string& s)//s2(s1)
:_str(new char[s._capacity+1])//capacity存储有效数据空间,每次都多开一个\0
,_size(s._size)
,_capacity(s._capacity)
{
strcpy(_str, s._str);
}
正确的现代写法 --利用构造函数swap
把随机数换给tmp导致程序崩溃--析构释放随机空间
string(const string& s)//s2(s1)
{
string tmp(s._str);//tmp是打工人,s._str是const字符串,相当于调用构造函数,s2想要一样大的空间和一样大的值
swap(_str, tmp._str);
swap(_size, tmp._size);
swap(_capacity, tmp._capacity);
}
再改进:放nullptr,delete nullptr不会报错
void swap(string& tmp)
{
::swap(_str, tmp._str);//::调用全局swap
::swap(_size, tmp._size);
::swap(_capacity, tmp._capacity);
}
string(const string& s)//s2(s1)
:_str(nullptr)
,_size(0)
,_capacity(0)
{
string tmp(s._str);//tmp是打工人,s._str是const字符串,相当于调用构造函数
swap(tmp);//s2和tmp交换
}
赋值运算符拷贝
默认的赋值代码崩溃原因:同样的浅拷贝报错,只是依次拷贝给s1,内存泄漏+析构两次
void test_string3()
{
string s1("hello world");
string s3("ww");
s1 = s3;
}
正确的普通写法(直接释放旧空间重新开辟)
自己给自己赋值(释放后随机值拷贝给自己)解决方法:判断相等
string& operator=(const string& s)
{
if (this != &s)
{
char* tmp = new char[s._capacity + 1];
//先开空间再释放,防止new失败抛异常破坏原数据
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;
}
return *this;
}
现代写法
1.错误的写法,此处swap包含赋值,死循环
string& operator=(const string& s)
{
if (this != &s)
{
string tmp(s);//调拷贝构造
::swap(*this,tmp);
}
return *this;
}
2.直接使用全局中的swap包含了一次拷贝构造,两次赋值,一共三次深拷贝,代价极高
正确的写法,swap成员变量换
void swap(string& tmp)
{
::swap(_str, tmp._str);//::调用全局swap
::swap(_size, tmp._size);
::swap(_capacity, tmp._capacity);