关于operator=的自我赋值问题

今天看了一段C++Primer的代码:p506

//use-counted assignment operator;use is a pointer to a shared use count
Sales_item&
Saler_item::operator=(const Sales_item &rhs)
{
	++*rhs.use;
	decr_use();
	p = rhs.p;
	use = rhs.use;
	return *this;
}
其中
void decr_use()
{
	if(--*use==0)
	{
		delete p;
		delete use;
	}
}
问题是:上面是如何处理自我赋值问题的。我看了半天,不太理解。

后来才发现:它所谓的防止自我赋值的核心问题就是要防止自我赋值过程中,被赋值对象被提前删除,而造成程序出错。注释后结果:

//use-counted assignment operator;use is a pointer to a shared use count
Sales_item&
Saler_item::operator=(const Sales_item &rhs)
{
	++*rhs.use; //右操作数的使用计数加1,这样就可以避免左右操作数相同,造成左操作数提前析构
	//因为调用decr_use后,左操作数就至少是2了,减1后不为零,就不会出现delete操作
	decr_use(); //这个decr_use是左操作数调用的,左操作数的使用计数减1
	p = rhs.p;  //将右操作数的指针赋给左操作数
	use = rhs.use;
	return *this;//返回左操作数的引用
}
其中
void decr_use()
{
	if(--*use==0)
	{
		delete p;
		delete use;
	}
}

现在来看Meyers的Effective C++中的“自我赋值”处理   p54

看如下代码:

Widget&
Widget::operator=(const Widget&rhs)
{
	delete pb;   //停止使用当前的bitmap
	pb = new Bitmap(*rhs.pb);//使用rhs的bitmap副本
	return *this;
}

这里的自我赋值问题是,operator=函数内的*this(赋值的目的端)和rhs有可能是同一个对象。果真如此delete就不只是销毁当前对象的bitmap,它也销毁rhs的bitmap。在函数末尾,Widget——它原本不该被自我赋值动作改变的——发现自己持有一个指针指向一个已被删除的对象。

欲阻止这种错误,传统做法是借有operator=最前面的一个证同测试达到自我赋值的检验目的:

Widget&
Widget::operator=(const Widget&rhs)
{
	if (this==&rhs) return *this;//证同测试
	delete pb;   //停止使用当前的bitmap
	pb = new Bitmap(*rhs.pb);//使用rhs的bitmap副本
	return *this;
}
不过这一改进仍有一个麻烦,那就是当new Bitmap出现异常(不论是因为分配时内存不足或因为Bitmap的copy构造函数抛出异常),Widget最终会持有一个指针指向一块被删除的Bitmap。这样的指针是有害的。你无法安全删除它们,甚至无法安全读取它们。那么,我们要做的就是让operator=具有异常安全性,而且在operator=具有异常安全性后往往能够自动获得“自我赋值安全”的回报。修改如下:

Widget&
Widget::operator=(const Widget&rhs)
{
	Bitmap* pOrig = pb;
	pb = new Bitmap(*rhs.pb);//使用rhs的bitmap副本
	delete pOring;
	return *this;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值