C++ 深浅拷贝及引入计数的写时拷贝

深浅拷贝

拷贝构造函数其实是构造函数的重载,参数类型为(const 类名&形参名),只有一个参数,且必须是引用传参,如果是传值传参,就会引起无限调用

当没有自定义拷贝构造函数的时候,系统就会调用默认的拷贝构造函数 且为浅拷贝(也称位拷贝)

浅拷贝可以实现普通的拷贝构造,但是一旦成员变量中含有指针,则切记不能用默认的拷贝构造(即浅拷贝)

当类的成员变量有指针时,浅拷贝仅仅将新生成的指针和旧指针指向同一个内存单元,不会另开辟空间,因此一旦发生析构,就会出现崩溃

1.因为两个指针指向的是同一内存单元,一旦当一个析构完成后,另一个再析构时,因为找不到所指向的单元,就会发生错误,并导致该指针的内存单元内存泄漏

2.因为指向的是同一个内存单元,一旦一个发生更改,另一个的值也会发生更改

因此深拷贝的作用意义重大

深浅拷贝代码:

class String

{

public:

String(const char* str)

:_str(new char[strlen(str) + 1])

{

strcpy(_str, str);

}



String(const String& s) //  1.浅拷贝

:_str(s._str)

{}

String(const String&s){ //  1.深拷贝

_str=new char[strlen(s._str)+1];

strcpy(_str,s._str);

}



String& operator=(const String& s) //   2.浅拷贝

{

if (this != &s)

{

_str = s._str;

}

return *this;

}

String &opreator=(const String&s){ //     2.深拷贝

if(this !=&s){

delete _str; //这一步重新释放并置空再创建是因为在构造新对象时,调用的是默认的构造函数,给_str开辟的大小不一定是合适的,需要重新分配下

_str=NULL;

_str=new char[strlen(s.str)+10];

strcpy(_str,s._str);

}

return *this;

}

~String()

{

if (_str)

{

delete[] _str;

}

_str = NULL;

}

private:

char* _str;

};

 

引入计数的写时拷贝

 

写时拷贝主要是综合了浅拷贝和深拷贝,即不会导致复制出来的变量同时指向一个内存空间导致访问出错,又避免了多次深拷贝开辟空间导致增加时耗的现象

写时拷贝的实现原理是通过引入一个 int*_refCount  来对一个内存空间进行监视,先是浅拷贝不考虑同时指向的问题,当该内存空间只被一次指向的时候为1,可直接析构证明无同时指向的现象,当解引用发现是2时,证明此时有两个指针同时指向这片空间,再进行深拷贝开辟空间来避免此问题。

写时拷贝代码:

class String

{

public:

String(char* str="")

:_str(new char[strlen(str)+1])

, _refCount(new int(1)) //引用计数的初始值为1

{

strcpy(_str, str);

}



//拷贝构造 s1(s2),采用浅拷贝

String(const String& s)

:_str(s._str)

, _refCount(s._refCount)

{

++(*_refCount);

}



//s1=s2(先将_str指向空间的引用计数--,然后看那个空间的引用计数是否为0,如果为0,则将该空间释放,然后将s的值和引用计数赋值给_str

String& operator=(const String& s)

{

if (_str != s._str)

{

if (--(*_refCount) == 0)

{

delete[] _str;

delete _refCount;

}

_str = s._str;

_refCount = s._refCount;

++(*_refCount);

}



return *this;

}



~String() //先将自己的引用计数--,然后看该引用计数是否为0,如果为0,则将该空间释放

{

if (--(*_refCount) == 0)

{

delete[] _str;

delete _refCount;

}

}



void CopyOnWrite() //只有当引用计数大于1时才开空间,如果引用计数等于1,说明当前空间只有自己一个对象指向它,直接可以对这个空间进行操作

{

if (*_refCount > 1)

{

char* newstr = new char[strlen(_str) + 1];

strcpy(newstr, _str);

_str = newstr;

_refCount = new int(1);

}

}

private:

char* _str;

int* _refCount;

};

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值