写时拷贝
在前面,我们模拟实现String类的时候,我们分析过,必须用深拷贝,如果用简单的浅拷贝就会导致程序崩溃,原因看下图:
如果我们解决了上面提到的两个问题,那么就可以用浅拷贝,首先要解决第一个问题:
(1):析构
我们需要知道当前对象析构后,还有没有对象指向这段空间,如果还有,就不用真正意义上的析构,如果就剩它一个指向这段空间,则要真正意义上的析构,不然就会导致内存泄漏。
那么要知道一共有多少个对象指向它,就需要就一个计数器,多一个对象指向它,就让计数器++
析构一个指向这段空间的对象,就让这个计数器- -,如果计数器为0,那么就释放这段空间,否则就会造成内存泄漏。
要实现这个计数器
(1):可以参考new [ ] 的机制,
如果不知道,可以看这个博客:
[enter link description here]
(http://blog.csdn.net/lrving_j/article/details/78403385)多开四个字节的空间。
(2):也可以加一个成员变量指向一段动态开辟的空间。
(2):其他对象 ”值 “的改变不影响我
真正意义上的写时拷贝,从字面的意思上来看,写时拷贝就是在对这段空间里存放的值进行改变时,就要拷贝;
具体代码实现:
方案一:
方案一:
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
class String
{
public:
String(char* str = "")
:_str(new char[strlen(str)+1])
,_refCount(new int(1))
{
strcpy(_str,str);
}
String(String& s)
:_str(s._str)
,_refCount(s._refCount)
{
(*s._refCount)++;
}
~String()
{
cout<<"hehe"<<endl;
if(--(*_refCount) == 0)
{
cout<<"OK"<<endl;
delete _str;
delete _refCount;
}
}
String& operator= (String& s)
{
if(this != &s)
{
if(--(*_refCount) == 0)
{
delete _str;
delete _refCount;
}
_str = s._str;
(*(s._refCount))++;
_refCount = s._refCount;
}
return *this;
}
char* GetString()
{
return _str;
}
char& operator[](size_t pos)//在修改内容时,重新开辟一段空间,也就是“写时拷贝”
{
String tmp(_str);
_str = new char[strlen(tmp._str)+1];
strcpy(_str,tmp._str);
*_refCount = 1;
return _str[pos];
}
private:
char* _str;
int* _refCount;//指向一个动态开辟4个字节的空间(计数器)
};
int main()
{
String s("hello");
String b = s;
cout<<s.GetString()<<endl;
cout<<b.GetString()<<endl;
s.operator[](2) = 'o';
return 0;
}
方案二:
多开辟四个字节的空间,类似于new [ ] 的机制
#include <iostream>
using namespace std;
class String
{
public:
String(char* str = "")
:_str(new char[strlen(str)+5])
{
strcpy(_str+4,str);
*(int*)_str = 1;
_str += 4;
}
String(String& s)
:_str(s._str)
{
(*(int*)(_str-4))++;
}
~String()
{
if(--(*(int*)(_str-4)) == 0)
{
delete (_str-4);
}
}
String& operator=(String& s)
{
if(this == &s)
return *this;
if(--(*(int*)(_str-4)) == 0)
{
delete (_str-4);
}
_str = s._str;
(*(int*)(_str-4))++;
return *this;
}
char& operator[](size_t pos)
{
if(*(int*)(_str-4) == 1)
{
return _str[pos];
}
else
{
String tmp(_str);
_str = new char[strlen(tmp._str)+5];
strcpy(_str+4,tmp._str);
*(int*)_str = 1;
_str += 4;
return _str[pos];
}
}
private:
char *_str;
};
int main()
{
String s("hello");
String a("world");
s = a;
s.operator[](1) = 'p';
return 0;
}