1、概念:因为浅拷贝的缺陷,所以在这个时候我们就引入了引用计数的拷贝。
【说明】:引用计数的拷贝是用来解决浅拷贝存在的问题的,所以它也是一种浅拷贝
2、如何实现:我们为每个内存的字符数组添加一个引用计数pcount,即就是在构造函数申请空间的时候多申请出来4个字节。表示有多少个对象使用这块内存,有多少个对象使用,就让pcount值加1,当对象被析构的时候,让pcount值减1,当pcount值为0的时候,将这块内存释放掉。当然pcount也要实现内存共享,所以它也是一个堆中的数据,每个对象都有一个指向它的指针。
3、【说明】:但在此时,pcount的类型的选取,就会要有所考虑?
1)如果选取int类型:(不采取)
#include<iostream>
using namespace std;
class String
{
public:
//构造函数
String(const char* ptr = "")
{
if(ptr == NULL)
{
_ptr = new char[1];
_pcount = 1;
*_ptr = '\0';
}
else
{
_pcount = 1;
_ptr = new char[strlen(ptr)+1];
strcpy(_ptr,ptr);
}
}
//拷贝构造函数
String(String& s)
:_ptr(s._ptr)
,_pcount(s._pcount)
{
_pcount++;
}
//赋值运算符重载
String& operator=(const String& s)
{
if(this != &s)
{
if(--_pcount == 0)
{
delete[] _ptr;
//delete _pcount;
}
else
{
_ptr = s._ptr;
_pcount = s._pcount;
(_pcount)++;
}
}
return *this;
}
//析构函数
~String()
{
if((0 == --_pcount) && _ptr!= NULL)
{
delete[]_ptr;
//delete _pcount;
_ptr = NULL;
}
}
//重载[]
char& operator[](size_t size)
{
if(--_pcount >1)
{
char* ptemp = new char[strlen(_ptr)+1];
int pcount = 1;
strcpy(ptemp,_ptr);
_pcount--;
_ptr = ptemp;
_pcount = pcount;
}
return _ptr[size];
}
private:
char*_ptr;
int _pcount;
};
void FunTest()
{
String s1("hello");
String s2(s1);
String s3(s2);
s3 = s2;
}
int main()
{
FunTest();
return 0;
}
2)如果选取的是static类型的:(不采取)
#include<iostream>
using namespace std;
class String
{
public:
//构造函数
String(const char* ptr = "")
{
if(ptr == NULL)
{
_ptr = new char[1];
_pcount = 1;
*_ptr = '\0';
}
else
{
_pcount = 1;
_ptr = new char[strlen(ptr)+1];
strcpy(_ptr,ptr);
}
}
//拷贝构造函数
String(String& s)
:_ptr(s._ptr)
{
_pcount++; //因为是静态的,所以直接进行计数的增值就可以了
}
//赋值运算符重载
String& operator=(const String& s)
{
if(this != &s)
{
if(--_pcount == 0)
{
delete[] _ptr;
//delete _pcount;
}
else
{
_ptr = s._ptr;
_pcount = s._pcount;
(_pcount)++;
}
}
return *this;
}
//析构函数
~String()
{
if((0 == --_pcount) && _ptr!= NULL)
{
delete[]_ptr;
//delete _pcount;
_ptr = NULL;
}
}
//重载[]
char& operator[](size_t size)
{
if(--_pcount >1)
{
char* ptemp = new char[strlen(_ptr)+1];
int pcount = 1;
strcpy(ptemp,_ptr);
_pcount--;
_ptr = ptemp;
_pcount = pcount;
}
return _ptr[size];
}
private:
char*_ptr;
static int _pcount;
};
int String::_pcount = 0;
void FunTest()
{
String s1("hello");
String s2(s1);
String s3(s2);
s3 = s2;
String s4("world");
String s5(s4);
}
int main()
{
FunTest();
return 0;
}
3)那么我们这样想:如果一个对象第一次开辟空间存放字符串再开辟一块新的空间存放新的额引用计数,当它拷贝构造其它对象时让其它对象的引用计数都指向存放引用计数的同一块空间,pcount设置成int*就可以啦,但是这种方式有缺陷。(读者可以自己实现下)
缺陷一:每次new两块空间,创建多个对象的时候效率比较低
缺陷二:它多次分配小块空间,容易造成内存碎片化,导致分配不出来大块内存