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时,进行分离