浅拷贝使多个对象共用一块内存地址,调用析构函数时导致一块内存被多次释放,导致程序奔溃。实现string类的时候通常显示的定义拷贝构造函数和运算符重载函数。
在我们在不需要写,只是读的时候就可以不用新开辟内存空间,就用浅拷贝的方式创建对象,当我们需要写的时候才去新开辟内存空间。这种就是写时拷贝。在构造函数中开辟新的空间时多开辟4个字节的空间,放在内存单元首部,用来存放引用计数器,记录这快空间的引用次数。
#include <iostream>
using namespace std;
#include <string.h>
class String{
public:
String(char*str=null)
{
ptr=(char*)malloc(strlen(str)+1+4);
*(int*)ptr=1;
ptr+=4;
strcpy(ptr,str);
}
~String()
{
if(ptr!=NULL)
_Realease();
}
String(const String&rhs)
{
ptr=rhs.ptr;
++(*(int*)(ptr-4));
}
String& operator=(const String&rhs)
{
if(this!=&rhs)
{
_Realease();
ptr=rhs.ptr;
++(*(int*)(ptr-4));
}
return *this;
}
char& operator[](int index)//写时拷贝
{
if (*(int*)(ptr-4)>1)//当引用次数大于1时新开辟内存空间
{
--*(int*)(ptr-4);//原来的空间引用计数器减1
char *str = (char*)malloc(strlen(ptr) + 5);
strcpy(str+4, ptr);
str+=4;
(*(int*)(str-4))++;//新开辟内存引用计数加一
}
return ptr[index];
}
friend ostream& operator<<(ostream& output, const String& str)
{
output << str.ptr;
return output;
}
private:
char*ptr;
void _Realease()//减引用计数
{
int count=*(int*)(ptr-4);
if((--count)==0)
{
free(ptr-4);
ptr=NULL;
}
}
};
int main()
{
String str1("lkd251");
String str2(str1);
String str3=str1;
String str4("sddefsdfrv2e2e2r3");
std::cout<<str1<<" "<<str4[4]<<std::endl; //lkd251 k
return 0;
}