对类的拷贝分为深拷贝和浅拷贝,深拷贝是新开辟一个空间存放数据,而浅拷贝是共享一个空间存放数据。浅拷贝更节省空间,而深拷贝的可靠性高,安全性高。为了解决浅拷贝的安全问题,我们使用引用计数器的方法。
引用计数器:
定义String_rep类,将String类设置为友元类,方便String类操作其私有成员
私有成员变量:字符指针m_data存放数据,use_count用来计数
class String_rep
{
friend class String;
public:
String_rep(const char* str = "")
{
m_data = new char[strlen(str) + 1];
strcpy(m_data, str);
increment();
}
~String_rep()
{
delete[]m_data;
m_data = NULL;
}
void increment()
{
use_count++;
}
void decrement()
{
if (--use_count == 0)
{
delete this;
}
}
private:
char* m_data;
int use_count;
};
成员函数increment()和decrement()用来改变计数
构造函数:用字符串初始化构造,开辟空间,并将字符串拷贝至空间,调用increment()引用计数器计数+1
析构函数:当引用计数器为零的时候调用析构函数释放空间
String类:
class String
{
friend ostream& operator<<(ostream& out,const String &s);
public:
String(const char* str = "")
{
rep = new String_rep(str);
}
String(const String& s)
{
rep = s.rep;
rep->increment();
}
String& operator=(String& s)
{
rep->decrement();
rep = s.rep;
rep->increment();
return *this;
}
~String()
{
rep->decrement();
}
void to_upper()
{
//写实拷贝
if (rep->use_count > 1)
{
String_rep* new_rep = new String_rep(rep->m_data);
rep->decrement();
rep = new_rep;
rep->increment();
}
char* ch = rep->m_data;
while( *ch != '\0')
{
if (*ch >= 'a' && *ch <= 'z')
{
*ch -= 32;
ch++;
}
}
}
private:
String_rep* rep;
};
String类用字符串构造函数,创建一个自己的引用计数器,当有对象拷贝构造时,对象的引用计数器指向被拷贝的引用计数器rep,并使引用计数器+1,若是赋值函数则当前引用计数器-1并使指向拷贝的引用计数器同时引用计数器+1
写实拷贝:
如例子,我们想将对象的m_data的小写改为大写,但是因为我们使浅拷贝,使用的是共同的空间,如果改变一个对象的m_data就会改变全部对象的m_data,为了防止这种情况发生,我们使用写实拷贝计数:
如果引用计数器为1,则说明只有1个对象,没有对象拷贝构造,直接更改
若大于1,则创建新的引用计数器,将当前的引用计数器减1,并指向新的计数器,新的计数器+1
void to_upper()
{
//写实拷贝
if (rep->use_count > 1)
{
String_rep* new_rep = new String_rep(rep->m_data);
rep->decrement();
rep = new_rep;
rep->increment();
}
char* ch = rep->m_data;
while( *ch != '\0')
{
if (*ch >= 'a' && *ch <= 'z')
{
*ch -= 32;
ch++;
}
}
}