**一、淺拷貝:**
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);
}
}
引用計數導致的改一塊兩塊一塊改的問題
寫時拷貝:
調試結果:
圖解: