if (_str)
{
_str = new char[1];
*_str = '\0';
}
| |
v v
if (_str)
{
_str = "";
}
~String()
{
if(_pStr)
delete[] _pStr;
}
实现string类反例:浅拷贝 (共享空间,销毁时free多次) eg:拷贝美人鱼的上半身
eg: String s1("hello");
String s2(s1);
String s3 = s1;
默认拷贝构造函数使用的是浅拷贝。
解决方法:深拷贝(创建一个新的空间) eg:拷贝美人鱼不为人知的下半身
String(const String& s)
:_str(new char[strlen(s._str) + 1])
{
strcpy(_str, s._str);
}
注意点:赋值运算符的重载,考虑当前this对象和创建对象的地址是否一致.
(先释放_str空间,再重新开辟和_str同样大小的空间,最后strcpy)
// 有问题,如果没有申请到新的空间,然而之前的空间已经被释放掉了。
String& operator=(const String& s)
{
if (this != &s)
{
delete[] _str;
_str = new char[strlen(s._str) + 1];
strcpy(_str, s._str);
}
return *this;
}
// 解决方法:先申请空间,然后拷贝完成后再去释放,类似于单链表的任意结点插入。
String& operator=(const String& s)
{
if (this != &s)
{
char *pStr = new char[strlen(s._str) + 1];
strcpy(pStr, s._str);
delete[] _str;
_str = pStr;
}
return *this;
}
现代写法
// 拷贝构造
String(const String& str)
:_str(NULL)
{
String tmpStr(str._str);
swap(_str,tmpStr._str);
}
// 赋值重载
String& operator= (const String& str)
{
if (this != &str)
{
String tmpStr(str._str);
swap(_str,tmpStr._str);
}
return *this;
}
// 相当于在传值的时候就创建了一个临时对象
String& operator= (String str)
{
swap(_str,str._str);
return *this;
}
写时拷贝
String(const char* 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 (_str != s._str)
{
if (--(*_pcount) == 0)
{
delete[] _str;
delete _pcount;
}
_str = s._str;
_pcount = s._pcount;
++(*_pcount);
}
return *this;
}
~String()
{
if (--(*_pcount) == 0)
{
delete[] _str;
delete _pcount;
}
}
private:
char* _str;
int *_pcount;
如果一个类中涉及了资源的管理,就需要考虑深浅拷贝的问题。
引起原因:没有显示提供拷贝构造函数或者赋值运算符重载
编译器会合成一个默认的 浅拷贝
什么是浅拷贝?
位的拷贝->内存拷贝 多个对象共用一份资源,一份资源被销毁多次会造成程序崩溃。
什么是深拷贝?
传统写法
现代写法
string类
#include <string>
string str1("1234567890"); // "1234567890"
string str2; // ""
string str3(str1, 3, 3); // "456"
string str4(str1, 3); // "4567890" 如果第三个参数没有给出,那就表示从下标为3的位置开始,直到字符串结束。
size length都是求长度 resize更改size reserve更改capacity
连续空间,所以支持operator[],随机访问。 at也可以
append拼接 assign赋值 c_str使用C格式的字符串 find正向查找 rfind反向查找
string::iterator是一种类型 与指针类似
string::iterator it = str1.begin();
while (it != str1.end())
{
cout<<*it<<" ";
++it;
}
默认capacity是15
ListNode(const DataType& data = DataType()) 缺省值:如果是内置类型,那么值为0,如果是自定义类型,那么调用构造函数。
list不能直接使用++,因为不是连续空间。
string类大小是32字节。
vector list map
const DataType& Front()const // 存在const对象的const类型的变量