上篇博客http://blog.csdn.net/xiaodu655/article/details/78148833浅谈了浅拷贝与深拷贝,说明了浅拷贝存在的问题,下面就针对浅拷贝存在的问题给出了以下的解决方案—-引用计数。
以下为两个空间的计数:
具体的实现如下:
class String //两个空间计数
{
public:
String(const char*str = "") //构造函数
:_count(new int(1))
{
if (NULL == str)
{
_str = new char[1];
*_str = '\0';
}
else
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
String(const String&d) //计数
:_str(d._str)
, _count(d._count)
{
++*_count;
}
String &operator=(const String&d) //赋值运算符
{
if (this != &d)
{
if (--*_count == 0)
{
delete[]_str;
delete _count;
}
_str = d._str;
_count = d._count;
++*_count;
}
}
~String()
{
if (_str&&--*_count == 0)
{
delete[] _str;
_str = NULL;
delete[]_count;
_count = NULL;
}
}
private:
char*_str;
int* _count;//若给成静态的则其会成为全局的,程序会出现错误
};
写时拷贝如下图所示:
即为只开辟一块空间,但是会给引用计数开四个字节,具体的实现如下:
class String
{
public:
String(const char*str = "")
{
if (str == NULL)
str = "";
_str= new char[strlen(str) + 1 + 4]; //多开辟四个字节用来计数
_str += 4;//_str真正的位置
strcpy(_str, str);
*(int*)(_str - 4) = 1;//因为指针已经向后偏了四个字节
}
String(const String&s)
:_str(s._str)
{
++GetReference();
}
String&operator=(const String&s)
{
if (this != &s)
{
Release();
_str = s._str;
++GetReference();
}
return *this;
}
char &operator[](size_t idx)
{
//if ((idx > 0) && (idx < strlen(_str)))
if (GetReference() > 1)//GetReference()>1说明这块空间至少两个人在用
{
//--GetReference();//如果执行这一步将会多减掉一个空间
String str(_str);
swap(_str, str._str);
}
return _str[idx];
}
~String()
{
Release();
_str = NULL;
}
friend ostream&operator<<(ostream&_cout, String&d);
friend istream&operator>>(istream&_cin, String&d);
private:
int &GetReference() //引用计数。这段空间为堆上的空间,不受影响
{
return *(int*)(_str - 4);
}
void Release()
{
if (_str && (--GetReference() == 0))
{
_str -= 4;
delete[]_str;
}
}
char* _str;
};
ostream &operator<<(ostream&cout, String&d)
{
cout << d._str;
return cout;
}
istream&operator>>(istream&cin, String&d)
{
char str[20];
cin >> str;
d = str;
return cin;
}
void Test()
{
char str[] = "hello";
str[0] = 'p';
cout << str << endl;
String c1("hello");
c1[0] = 'n';
cout << c1 << endl;
String c2(c1);
cout << c2 << endl;
String c3;
c3 = c2;
c1[0] = 'n';//若上边函数不是传引用则其无法作为左值
cout << c3 << endl;
cout << c3[2] << endl;
}
int main()
{
Test();
system("pause");
return 0;
}
测试结果如下所示:
本人是新手,希望大家多多给予建议。