string實現
- string(const char* str)
- string(string&string)
- operator=(string &string)
- ~string()
爲什麼要有深拷貝?
淺拷貝
又稱爲位拷貝,是將資源按位拷貝,如果對象中管理資源,最後就會導致多個對象共享同一份資源,當一個對象銷燬時就會將該資源釋放掉,而此時另一些對象不知道該資源已經被釋放,造成重複釋放,例如
char c[] = "ada";
char *d = c;
因此有了深拷貝
#include <iostream>
#include <string>
#include <algorithm>
#pragma warning(disable:4996)
using namespace std;
namespace bit
{
class string
{
public:
string(const char* str= "")
{
if (str == nullptr)
{
_str = new char[1];
(*_str) = '\0';
}
else
{
_str = new char[strlen(str)+1];
strcpy(_str, str);
}
}
string(const string& S)
{
_str = new char[strlen(S._str) + 1];
strcpy(_str,S._str);
}
string& operator=(const string& S)
{
//if (&S != this)
//{
//
//
// char*_pstr = new char[strlen(S._str) + 1];
// delete[] _str;//釋放字符串用delete[]
// strcpy(_pstr, S._str);
// _str = _pstr;
// return *this;//舊時
//}
string strtmp(S);
swap(strtmp._str, _str);//新型
return *this;
}
~string()
{
if (_str)
{
delete[] _str;
_str = nullptr;
}
}
private:
char* _str;
};
}
int main()
{
bit::string a("hello world");
bit::string b(a);
bit::string c;
c = a;
b = a;
}
對於 a,b,c 每份資源都是獨立的因此不會造成重複釋放同一塊資源。
有沒有辦法使得淺拷貝也能防止資源的重複釋放?
可以參考智能指針,用一個標記確定當前有多少指針指向這個資源,當該標記爲0時,釋放該資源。
對於這個標記,可能有兩種方法能實現,一個是設置一個靜態變量 count ,第二個是設置一個int指針變量count。每有一個指針指向資源,使其+1.再考慮到某些情況,放棄第一種方案,有興趣的讀者可以想一想爲什麼?
namespace bit
{
class string
{
public:
string(const char* str = "")
{
if (str == nullptr)
{
_str = new char[1];
(*_str) = '\0';
}
else
{
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
*count = 1;
}
string(const string& S)
{
if (_str != nullptr && --(*count) == 0)
{
delete[] _str;
delete count;
_str = nullptr;
count = nullptr;
}
_str = S._str;
count = S.count;
(*count)++;
//cout << *count;
}
string& operator=(const string& S)
{
if (_str != nullptr && --(*count) == 0)
{
delete[] _str;
delete count;
_str = nullptr;
count = nullptr;
}
_str = S._str;
count = S.count;
(*count)++;//不能*count++,
return *this;
}
char& operator[](int i)
{
if (*count > 1)//?爲什麼大於1
{
bit::string S(_str);
Swap(S);
}
return _str[i];
}
char& operator[](int i) const
{
return _str[i];
}
~string()
{
if (_str && --(*count) == 0)
{
delete[] _str;
delete count;
_str = nullptr;
count = nullptr;
}
}
void Swap(bit::string S)
{
swap(_str,S._str);
swap(count, S.count);
}
private:
char* _str;
int* count = new int(0);
};
}
但是上面的代碼有一個很大的缺陷,當對於其中一個資源進行修改,會影響其他的資源,因此我們可以在寫的時候將這份資源分離,也就是寫時拷貝,Copy On Write,對[]進行重載,當*count的值大於2時,進行分離