**一、浅拷贝:**
1)代码:
1、构造:
String ::String(const char* str="")
:_str(new char[strlen(str)+1])
{
strcpy(_str, str);
}
2、拷贝构造
String::String(const String&s)
: _str(s._str)
{}
3、赋值浅拷贝
//s2==s1
String& String:: operator=(const String&s)
{
if (this!=&s)
{
_str = s._str;
}
return *this;
}
2)图解:
4、析构
String::~String()
{
if (_str)
{
delete[] _str;
}
}
由于浅拷贝会引发析构两次的问题 所以引入了引用计数,为了保证证每个对象的独立性,所以引入了写时拷贝,可以理解为引用计数和写时拷贝就是浅拷贝的一种优化。
二、引用计数与写时拷贝:
1)代码:
1、构造:
String::String(const char* str = "")//拷贝
:_str(new char[strlen(str)+1])
,_pCount(new int(1))//开辟1块空间并初始化为1
{
strcpy(_str, str);
}
2、拷贝构造:
String::String(const String&s)//拷贝构造
:_str(s._str)
,_pCount(s._pCount)
{
(*_pCount)++;
}
调试结果:
图解:
问题:一个改了会影响另一个
String s1("hello world");
String s2(s1);
s1[2] = 'x';
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
调试结果:
3、赋值运算符重载:
//s2=s1
String& String:: operator=(const String&s)//赋值运算符重载
{
if (this != &s)
{
if (--(*_pCount) == 0)//这里不调用析构函数,
//因为析构函数一般都是在出了函数作用域才被调用
{
delete[] _str;
delete _pCount;
}
_str = s._str;
_pCount = s._pCount;
++(*_pCount);
}
return *this;
}
String s1("hello world");
String s2(s1);
s1[2] = 'x';
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
调试结果:
图解:
4、写时拷贝(下开法):
void String::CopyOnWrite()
{
if ((*_pCount) > 1)
{
char*newstr = new char[strlen(_str) + 1];
strcpy(newstr, _str);
_str = newstr;
--(*_pCount);
_pCount = new int(1);
}
}
char& String::operator[](size_t pos)//可以修改字符串中的字符
{
CopyOnWrite();
return _str[pos];
}
为了解决两个程序会相互影响
调试结果:
图解:
5、析构:
String::~String()
{
if (--(*_pCount)==0)
{
delete[] _str;
delete _pCount;
_str = NULL;
_pCount = NULL;
}
}
三、深拷贝(传统写法和现代写法)
传统写法:
String::String(const char*str = "")
:_str(new char[strlen(str) + 1])
{
strcpy(_str, str);
}
//s2(s1)
String::String(const String& s)
: _str(new char[strlen(s._str)+1])
{
strcpy(_str, s._str);
}
//s3=s1
String& String::operator=(const String&s)
{
if (this!=&s)
{
char*str = new char[strlen(_str) + 1];
delete[] _str;
_str = str;
strcpy(_str, s._str);
}
return *this;
}
String::~String()
{
if (_str)
{
delete[] _str;
}
}
调试结果:
图解:
现代写法:
String::String(const char*str = "")
:_str(new char[strlen(str) + 1])
{
strcpy(_str, str);
}
//s2(s1)
String::String(const String& s)
: _str(NULL)
{
String tmp(s._str);
swap(tmp._str, _str);
}
//s1=s3
String& String::operator=(const String&s)
{
if (this != &s)
{
String tmp(s._str);
swap(_str, tmp._str);
}
return *this;
}
String::~String()
{
if (_str)
{
delete[] _str;
}
}
调试结果:
图解:
补充写时拷贝(头开法):
String::String(const char* str = "")
:_str(new char[strlen(str)+5])
{
_str += 4;
strcpy(_str, str);
*((int*)(_str-4)) = 1;
}
//s2(s1)
String::String(const String& s)
:_str(s._str)
{
*((int*)(_str-4)) += 1;
}
//s1=s2
String& String ::operator=(const String& s)
{
if (this!=&s)
{
if (--(*(int*)(_str - 4)) == 0)
{
delete[](_str - 4);
}
_str = s._str;
++(*(int*)(_str - 4));
}
return *this;
}
void String::CopyOnWrite()
{
if ((*(int*)(_str-4))>1)
{
char* newstr = new char[strlen(_str) + 5];
strcpy(newstr, _str);
--(*(int*)(_str - 4));
_str = newstr;
++(*(int*)(_str - 4));
}
}
char &String::operator[](size_t pos)
{
CopyOnWrite();
return _str[pos];
}
String::~String()
{
if (--(*(int*)(_str-4))==0)
{
delete[] (_str-4);
}
}
引用计数导致的改一块两块一块改的问题
写时拷贝:
调试结果:
图解: