C++之深、浅拷贝

    先给出一段程序:

void fun()
{
	int *pTest1 = new int[10];
	int *pTest2 = pTest1;
	delete[] pTest1;
	delete[] pTest2;
}
int main()
{
	fun();
	return 0;
}

      以上程序运行会崩溃,由于简单的“ = ”只能将pTest1和pTest2指向同一块空间,没有给pTest2开辟新的空间,所以,在delete对象时,该空间被释放了两次,因此,程序崩溃。

    在类中,更容易出现这种情况,例如以下程序:

class String
{
public:
	String(const char * pData = "")
		: _pData(new char[strlen(pData) + 1])
	{
		strcpy(_pData, pData);
	}
	String(const String& _string)
	{
		if (this != &_string)
		{
			_pData = _string._pData;
		}
	}
	~String()
	{
		if (NULL != _pData)
		{
			delete[] _pData;
			_pData = NULL;
		}
	}
private:
	char *_pData;
};
void FunTest()
{
	String s1;
	String s2("hallo world");
	String s3(s2);
}
int main()
{
	FunTest();
}
    程序运行后,会出现崩溃。分析FunTest函数:

    String s1:调用构造函数,由于没有参数,在构造函数内有缺省参数,所以,将S1的_pData赋为空。

    String s2("hallo world"):调用构造函数,给_pData分配空间,将形参的内容拷贝到_pData中。

    String s3(s2):调用拷贝构造函数,将s3的_pData指向形参的_pData,即s3._pData指向s2._pData。所以,两个指向的是同一块空间。

    当程序继续往下执行时,局部变量s3被析构,调用析构函数,将s3._pData所指向的空间释放,并将s3._pData赋为NULL。当s2被析构,调用析构函数,因为s2._pData一直指向申请空间,s2._pData不为空,现在又要去释放已经被s3._pData释放的空间,所以会出现问题。

    当类里面有指针对象时,拷贝构造和赋值运算符重载只进行值拷贝(浅拷贝),两个对象指向同一块内存,对象销毁时该空间被释放了两次,因此程序崩溃!

        String s3(s2);
        String s4=s3;

    浅拷贝:编译器只是直接将指针的值拷贝过来,结果多个对象共用同一块内存,当一个对象将这块内存释放掉之后,另一些对象不知道该块空间已经还给了系统,以为还有效,所以在对这段内存进行操作的时候,发生了访问违规。

    要想解决这一问题,就得进行深拷贝,也就是在拷贝构造函数和赋值运算符重载的实现时,申请新的空间,并把要拷贝的对象的值复制一份放入新开辟的空间中,例如以下程序:

class String
{
public:
	char* _pstr;
public:
	String(char* pstr="")
	{
		if (pstr == NULL)
		{
            _pstr = new char[1];
			*_pstr = '\0';
		}
		else
		{
			_pstr = new char[strlen(pstr) + 1];
			strcpy(_pstr,pstr);
		}
	}
	String(const String&s)
	{
		_pstr = new char[strlen(s._pstr) + 1];
		strcpy(_pstr, s._pstr);
	}
	String& operator = (const String& s)
	{
		if (this != &s)
		{
			char *pstr = new char[strlen(s._pstr) + 1];
			strcpy(pstr, s._pstr);
			delete[] _pstr;
			_pstr = pstr;
		}
		return *this;
	}
};<pre name="code" class="cpp">int main()
{
	String s1("hallo world");
	cout << s1._pstr << endl;
	String s2(s1);
	cout << s2._pstr << endl;
	String s3 = s2;
	cout << s3._pstr << endl;
	return 0;
}

 

    在这个程序之中,拷贝构造函数和赋值运算符重载都分配了新的空间,并拷贝了值,这样使得在对象使用完成后进行析构时,不会多次析构一个空间而出现错误,s1、s2、s3各都指向自己的数据块,析构时,释放各自的空间。这也就是深拷贝。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值