Effective C++ — 构造/析构/赋值运算(二)

Effective C++ 

———————————————————————


条款11:在operator=中处理"自我赋值"


有的人可能想了,有谁会写出 a = a;这种表达式这个条款是拿来充数的吧? 你还真的别这么说,这种情况还真的有情

况发生.比如有 的自我赋值你根本看不出来:比如:

a[i] = a[j]; //潜在的自我赋值,如果i = j的时候.

*px = *py;  // 潜在的自我赋值,如果px和py恰巧指向同一个东西.

这些都不是明显的自我赋值,是"别名"带来的结果.一般而言当某段代码操作Points和reference而他们被用来"指向多

个相同类型的对 象",就需要考虑这些对象是否为同一个.实际上两个对象只要来自同一个继承体系,他们甚至不许声明

为相同类型就可能造成"别名" 因为一个base class的reference或者points可以指向derived class对象.

我们一般的operator=实现代码为:

widget& operator=(const widget& rhs)
{
	delete pb;  //假设pb为管理资源的指针
	pb = new Bitma(*rhs.pb);
	return *this;
}

但是如果不慎出现别名,那么你是先删除掉自己然后再自己对自己赋值? 让自己的指针指向一个被销毁的地方? 所以

我们需要加 上一层判断.

widget& operator=(const widget& rhs)
{
	if (this == &rhs)
	{
		return *this;
	}
	delete pb;  //假设pb为管理资源的指针
	pb = new Bitma(*rhs.pb);
	return *this;
}

这样做是一点问题都没有的,但是这个新版本会存在异常方面的麻烦.更明确的说,如果"new Bitma"导致异常,widget最终会持有

一个指针指向一块被删除的bitmap.这样的指针是有害的,你无法安全的删除它们,甚至无法安全的读取他们.唯一能对他们做的安

全事件是付出许多调试能力找出错误根源.

如果你为了让operator= 具有"异常安全性,所以我们只需要注意在复制pb所指东西之前别删除pb:

widget& operator=(const widget& rhs)
{
	Bitma* porig = pb; //假设pb为管理资源的指针
	pb = new Bitma(*rhs.pb);
	delete porig;  
	return *this;
}

现在,如果"new Bitma"抛出异常,pb保持原状.即使没有证同测试,这段代码还是能够处理自我赋值,因为我们对原pb做了一件

复件,然后重新定义pb,最后pb定义好了之后,删除掉复件. 它或许不是处理"自我赋值"的最高效方法,但它行得通.

总结:

确保当对象自我赋值时operator有良好的行为,检查他是否存在自赋值.

确定任何函数如果操作一个或一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确.



条款12:复制对象时勿忘其每一个成分



设计良好之面向对象系统会将对象的内部封装起来,只留下两个函数负责对象拷贝,那就是copy构造函数和

copy assignment操作符 我称他们为copying函数.


如果你声明自己的copying函数,意思就是告诉编辑器你并不喜欢却省实现中的某些行为。编译器就会觉得被冒犯一

样,会用一种奇 怪的方式来回敬你,当你的代码出现一点错误的时候却不告诉你.


我就这样说吧,当你编写一个copying函数请确保两件事情:

1.复制所有的local成员变量.

2.调用所有base classes内的适当的copying函数.


其实两个copying函数往往拥有相同的实现本体,这可能会引诱你让某个函数去乔勇另一个函数以避免代码重复.这样

精益求精的态 度值得赞赏,但是令某个copying函数调用一个copying函数却无法让你达到你想要的目标.


令copy assignment操作符调用copy构造函数是不合理的,因为这就像试图构造一个已经存在的对象.这挺起来就很不

通顺.单纯的接 受这个建议:你不该令copy assignment操作符调用copy构造函数.


令copy构造函数调用copy assignment操作符同样没有意义.构造函数是用来初始化新对象,而assignent操作符知识

性于已初始化对 象身上.对应尚未构造好的对象赋值,就像在一个尚未初始化的对象身上做"只对已初始化对象才有意

义"的事情一样.同样无聊. 如果你发现你的copy构造函数和 copy assignment操作符有相近的代码,消除重复代码的做

法就是建立一个新的成员函数给两者调用 这样的函数往往是private而且常被命名为init. 你可以尝试这样.


总结:


Copying函数应该确保复制"对象内的所有成员变量"及"所有base class 成分"

不要尝试以某个copying函数实现另一个copying函数,应该将共同的机能放进第三个函数当中.









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明
有效的C++ STL是指标准模板库(Standard Template Library),它是C++编程中广泛使用的一组模板类和函数的集合,提供了一些常用的数据结构和算法实现,通过使用STL,程序员可以更加高效地开发出稳定、可读性强且可重用的代码。 STL包括了三个主要组件:容器(Container)、算法(Algorithm)和迭代器(Iterator)。 容器是STL的基础,它提供了一系列的数据结构,如vector、list、map等,可以用来储存和操作各种类型的数据。 算法提供了一组通用算法,如排序、查找、拷贝、删除等等,可以直接应用于各种容器中的数据,使得程序员不需要自己实现这些基本算法,从而节省了开发时间。 迭代器是STL的一个重要概念,它可以将容器和算法进行有效地连接,通过迭代器,程序员可以以一种统一的方式来访问和操作容器中的元素,无需关心容器内部的具体实现。 使用STL,程序员可以极大地提高编程效率和代码质量。STL的模板类和函数经过了大量的测试和调试,保证了它们的稳定性和可靠性。此外,STL还具有高度的可重用性,程序员可以在不同的项目中重复使用同样的代码,从而减少了代码的重复编写和维护成本。 总之,STL是一种高效的C++编程工具,它通过提供一组模板类和函数,为程序员提供了各种常用的数据结构和算法实现,使得程序员能够更加高效地开发出稳定、可读性强且可重用的代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值