Effective C++ — 构造/析构/赋值运算(二)
来源:互联网 发布:hdmi网络高清传输器tx 编辑:程序博客网 时间:2024/05/18 01:45
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
- Effective C++(二)构造/析构/赋值运算
- 【读书笔记】Effective C++-2 构造/析构/赋值运算(之二)
- Effective C++(二)构造/析构/赋值运算
- Effective C++ <二>:构造,析构,赋值运算
- effective c++-构造/析构/赋值运算
- 《Effective C++》构造、析构、赋值运算
- effective c++读书笔记二——构造/析构/赋值运算
- Effective C++ — 构造/析构/赋值运算(二)
- 《Effective C++》读书笔记(二) 构造/析构/赋值运算 (第一部分)
- Effective C++笔记: 构造/析构/赋值运算(二)
- Effective C++学习笔记二(构造/析构/赋值运算)
- Effective C++ 笔记二构造/析构/赋值运算
- Effective C++之二:构造/析构/赋值运算
- 【读书笔记】Effective C++-2 构造/析构/赋值运算(之一)
- 【读书笔记】Effective C++-2 构造/析构/赋值运算(之三)
- 【读书笔记】Effective C++-2 构造/析构/赋值运算(之四)
- 《Effective C++》第二章:构造/析构/赋值运算
- Effective C++ ——构造/析构/赋值运算符
- python-字典增删改查、遍历、方法、a,b=["dd","gg"]赋值方式
- [6-03]spring事务管理和框架整合
- 2017 ACM-ICPC 亚洲区(西安赛区)网络赛 F. Trig Function
- ffplay流程分析
- Linux STDIN_FILENO 和 STD
- Effective C++ — 构造/析构/赋值运算(二)
- CentOS下yum安装、源的选择及介绍
- Codeforces Round #434 (Div. 2)
- JS的基础
- MySql学习之Join查询
- 简单介绍线程池在并发编程中的使用
- 215. Kth Largest Element in an Array
- 事件句柄和支持他们的HTML元素
- sql server 去掉导入csv文件时去除数据上的引号