引用计数+写时拷贝

时间:2022-03-05 04:03:51

在我的理解来看,引用计数可以解决一块空间被多次释放的问题;写时拷贝可以解决一个对象内容改变影响另一个对象内容的问题。

  1. 针对一个对象空间有多个引用计数的问题,不会被多次释放。
    用静态的引用计数变量(只适合有一个对象空间)
#include<iostream>
using namespace std;

class String
{
public:
String(const char*str = "")
:_str(new char[strlen(str)+1])
{
_refCount = 1;
strcpy(_str, str);
}

String(const String& str)
:_str(str._str)
{
++_refCount;
}

//s1=s2
String& operator=(String& str)
{
if (_str != str._str)
{
_str = str._str;
_refCount = str._refCount;
++_refCount;
}
return *this;
}

~String()
{
if (--_refCount == 0)//当前置--为0时,意味着开辟的空间只被一个对象占有
{
delete[]_str;
}
}

void Display()
{
cout << _str << endl;
}
private:
char* _str;
static int _refCount; //静态成员变量只能在类外初始化。
//静态成员只存储在一处,是类的所有对象共享的成员,而不是某个对象的成员。
};

int String::_refCount = 0;//静态成员的初始化

int main()
{
String s1("hello");
String s2(s1);
String s5(s1);
String s6(s1);
s2.Display();

String s3("world");
String s4(s3);
s4.Display();
}

引用计数+写时拷贝

引用计数+写时拷贝

不足:当构造了两个对象空间时,两个对象空间有不同的引用计数,但是这里是共用一个引用计数,会相互影响。

2._refCount是指针变量,有自己单独的空间,每个对象都有自己的引用计数空间

#include<iostream>
using namespace std;

class String
{
public:
String(const char*str = "")
:_str(new char[strlen(str)+1])
, _refCount(new int(1))//开辟空间并初始化
{
strcpy(_str, str);
}

String(const String& str)//拷贝构造须传空间地址,引用计数地址
{
_str = str._str;
_refCount = str._refCount;
++*(_refCount);
}

String& operator=(const String& str)
{
if (_str != str._str)
{
if (--*(_refCount) == 0)//要是_str指向str须判断_str的引用计数是否为0
{
delete[]_str;
delete _refCount;
}
_str = str._str;
_refCount = str._refCount;
++*(_refCount);
}
return *this;
}

~String()
{
if (--*(_refCount) == 0)
{
delete[]_str;
delete _refCount;
}
}

void CopyOnWrite()//写时拷贝
{
if (*(_refCount) > 1)
{
char* tmp = new char[strlen(_str) + 1];
strcpy(tmp, _str);
--(*_refCount);

_str = tmp;
_refCount = new int(1);
}
}

void Display()
{
cout << _str << endl;
}

char& operator[](size_t pos)
{
CopyOnWrite();
return _str[pos];
}

char* Get_str()
{
return _str;
}
private:
char* _str;
int* _refCount;
};

int main()
{
String s1(" hello");
String s2(s1);
String s3(s1);
s1[0] = 'a';
s1.Display();
s2.Display();

String s4("world");
}

引用计数+写时拷贝

引用计数+写时拷贝

3.将引用计数的空间开辟在_str的空间的前面
这里一定要弄清楚啥时候是_str-4, 啥时候是_str.

#include<iostream>
using namespace std;

class String
{
public:
String(const char*str = "")
:_str(new char[strlen(str)+5])//为引用计数开四个字节空间,_str指向的是这块空间的头
{
*(int*)(_str) = 1;//对引用计数初始化
_str += 4;//指向的是真正字符数组的开始
strcpy(_str, str);
}

String(String& str)
{
_str = str._str;
++*(int*)(_str - 4);
}

String& operator=(String& str)
{
if (_str != str._str)
{
if (--*(int*)(_str - 4) == 0)
{
delete[](_str - 4);
}
_str = str._str;
++*(int*)(_str - 4);
}
return *this;
}

~String()
{
if (*(int*)(_str - 4) == 0)
{
delete[](_str - 4);
}
}

void CopyOnWrite()
{
if (*(int*)(_str - 4) > 1)
{
char* tmp = new char[strlen(_str) + 5];
tmp += 4;//才指向真正的字符数组的位置
strcpy(tmp, _str);
_str = tmp;
++*(int*)(_str-4);
}
}

char& operator[](size_t pos)
{
CopyOnWrite();
return _str[pos];
}

char* Get_str()
{
return _str;
}

void Display()
{
cout << _str << endl;
}
private:
char* _str;
};
int main()
{
String s1(" hello");
String s2(s1);
String s3(s1);
s1[0] = 's';
s1.Display();
s2.Display();
}