《Effective C++ 》学习笔记——条款11
***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************
二、Constructors,Destructors and Assignment Operators
Rule 11:Handle assignment to self in operator =
规则11:在 operator= 中处理“自我赋值”
1.自我赋值?!
比方这种:
class Widget { ... };
Widget w;
...
w = w; // 赋值给自己
这样做是同意的,所以不要期盼不会发生,由于鸟大了,什么林子都有 o(╯□╰)o。。
2.自我赋值 其它形式
① 除了最直观的 w=w
② 另一些隐蔽的,比方:
a[i] = a[j];
// 万一 i等于j
③ *px = *py
也许。这两个指针都指向同一个对象
④ 还有 base class 与 derived class的:(由于一个基类的引用或者指针。能够指向派生类对象)
class Base { ... };
class Derived : public Base { ... };
void doSomething( const Base& rb , Derived* pd);<span style="white-space:pre"> </span>// rb 和 pd 可能指向同一个对象
总结下来就是,假设某段代码操作pointers 或 references,而它们被用来“指向多个同样类型的对象”,就须要考虑这些对象是否为同一个,并且假设对象来自同一个继承体系。它们甚至不须要声明为同类型就可能造成“别名”(如上面的④)。
3.愚蠢的自我赋值,会导致?
class Bitmap { ... };
class Widget {
...
private:
Bitmap* pb;
};
Widget& Widget::operator=( const Widget& rhs )<span style="white-space:pre"> </span>// 一分不安全的 operator= 实现版本号
{
delete pb;<span style="white-space:pre"> </span>// 停止使用当前的 Bitmap
pb = new Bitmap(*rhs.pb);<span style="white-space:pre"> </span>// 使用 rhs's的Bitmap 副本
return *this;<span style="white-space:pre"> </span>// 这个问题在上一个条款(条款10)中介绍过
}
这个样例说明了虾米呢?
就是,假设是
a = b;
工作原理是。先把a的版本号删除。然后在将b赋值给a。
所以,假设a与b 是同一个东西,它就会导致错误,
按上面的样例来讲,就是,删除pb的同一时候。rhs也被删除了,所以第二行的赋值动作就会指向一个已经被删除的对象。
4.看到错误了,总归要解决的
有三种解决方式
<1> 第一种方案——“证同測试” identity test
Widget& Widget::operator=(const Widget& rhs )
{
if( this == &rhs ) return *this;<span style="white-space:pre"> </span>// identity test delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
就是在运行代码前。先推断是否是同一个东西,若是,就不须要做不论什么事情。直接返回。
<2> 另外一种方案——先赋值,再删除
Widget& Widget::operator=(const Widget& rhs)
{
Bitmap* pOrig = pb;<span style="white-space:pre"> </span>// 先备份
pb = new Bitmap(*rhs.pb);<span style="white-space:pre"> </span>// 赋值
delete pOrig;<span style="white-space:pre"> </span>// 删除备份
return *this;
}
就是仅仅须要注意在复制之前别删除原来的,先备份一下。
这也许不是处理“自我赋值”最高效的办法。但它行得通。
<3> 第三种方案——copy and swap
class Widget {
...
void swap( Widget& rhs );<span style="white-space:pre"> </span>// 交换*this和rhs的数据,在后面条款29会有具体解释
...
};
Widget& Widget::operator=( const Widget& rhs )
{
Widget temp(rhs);<span style="white-space:pre"> </span>// 为rhs数据制作一份复件
swap(temp);
return *this;
}
并且,还有还有一种形式。对于:①某class的 copy assignment操作符声明为“以 by value 方式接受实參”。②以by value方式 传递东西会造成一份复件:
Widget& Widget::operator= ( Widget rhs )<span style="white-space:pre"> </span>// rhs是被传递对象的一份复件
{<span style="white-space:pre"> </span>
swap(rhs);<span style="white-space:pre"> </span>// 注意这里是 pass by value
return *this;<span style="white-space:pre"> </span>// 将*this的数据和复件的数据互换
}
而这样的做法也是作者比較不推荐的。由于它为了 伶俐巧妙的修补 牺牲了 代码的清晰性。可读性略低。
但 将 copying 动作 从函数本体 移至 函数參数构造阶段 却能够 让编译器产生更高效的代码。
5.请记住
★ 确保当对象自我赋值时 operator= 有良好行为。当中技术包含比較“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap。
★ 确定不论什么函数假设操作一个以上的对象,而当中多个对象是同一个对象时,其行为仍然正确。
***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************
《Effective C++ 》学习笔记——条款11的更多相关文章
- effective C++ 读书笔记 条款11
条款11: 在operator= 中处理"自我赋值" 在实现operator=时考虑自我赋值是必要的就像 x=y .我们不知道变量x与y代表的值是否为同一个值(把x和y说成是一个指 ...
- Effective C++学习笔记 条款07:为多态基类声明virtual析构函数
一.C++明确指出:当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未定义——实际执行时通常发生的是对象的 ...
- Effective C++学习笔记 条款06:如不想使用编译器自动生成的函数,就该明确拒绝
一.为驳回编译器自动提供的机能,可将相应成员函数声明为private并且不予实现.(如果你仅仅是自己不实现的话,编译器会帮你实现) 如: class A { public: A(const strin ...
- Effective C++学习笔记 条款05:了解C++默默编写并调用的哪些函数
一.如果用户没有提供构造函数.copy构造函数.copy assignment操作符和析构函数,当且仅当这些函数被需要的时候,编译器才会帮你创建出来.编译器生成的这些函数都是public且inline ...
- Effective C++学习笔记 条款04:确定对象被使用前已先被初始化
一.为内置类型对象进行手工初始化,因为C++不保证初始化它们. 二.对象初始化数据成员是在进入构造函数用户编写代码前完成,要想对数据成员指定初始化值,那就必须使用初始化列表. class A { pu ...
- Effective C++学习笔记 条款02:尽量以const,enum,inline替换 #define
尽量使用const替换 #define定义常量的原因: #define 不被视为语言的一部分 宏定义的常量,预处理器只是盲目的将宏名称替换为其的常量值,导致目标码中出现多分对应的常量,而const定义 ...
- Effective STL 学习笔记 32 ~ 33
Effective STL 学习笔记 32 ~ 33 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...
- Effective STL 学习笔记: Item 22 ~ 24
Effective STL 学习笔记: Item 22 ~ 24 */--> div.org-src-container { font-size: 85%; font-family: monos ...
- ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM - ROSMapModify - ROS地图修改
ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM - 2 - MapModify地图修改 We can use gmapping model to genera ...
随机推荐
- LINQ Enumerable 续
筛选序列 Enumerable.Distinct 对于复杂的对象列表,运行时引擎如何才能通过比较确定两个对象是否重复?对于复杂对象,必须提供一个比较器,即实现IEqualityComparer(Of ...
- Struts2与jQuery.ajax()的结合
1.客户端是通过$.ajax()方法向login.action传递数据:2.其中action中execute()方法返回值为空,并通过[ServletActionContext.getResponse ...
- 图文教程:手把手教你用U盘安装Ubuntu
说到ubuntu,有接触linux的童鞋都应该听过,用wubi安装只是像在电脑上安装一个软件,可以轻松体验ubuntu,不过毕竟性能会打折扣,所以本人是比较喜欢直接安装在硬盘上的. 这种方法只适合用d ...
- ExtJS实例1
1.创建一个Extjs的Window,用ajax请求HTML文件,并执行HTML的代码和脚本 窗体中文字是从一个HTML中获取,并且HTML中执行脚本使窗体高亮1秒 主页面: <!DOCTYPE ...
- 传输层-TCP
UDP协议提供了端到端之间的通讯,应用程序只需要在系统中监听一个端口,便可以进行网络通讯.随着计算机网络的发展,计算机网络所承载的业务越来越多,有些业务数据的传输需要具备可靠性,譬如我们在进行在线聊天 ...
- ubuntu 下源码安装Postgreql pgAdmin3
一.安装 PostgreSQL 1.安装相关依赖,在终端下执行: sudo apt-get install zlib1g-dev sudo apt-get install libreadline ...
- php获取mac用于网站绑定服务器
php获取mac用于网站绑定服务器 <?php class GetMacAddr{ var $return_array = array(); // 返回带有MAC地址的字串数组 var $mac ...
- "float: left;" div 不换行显示
<div id='p'> <div id='c1'> </div> <div id='c2'> </div> <div id='c3' ...
- 2013 多校联合2 D Vases and Flowers (hdu 4614)
Vases and Flowers Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others ...
- 《python基础教程》笔记之 字符串
字符串格式化 字符串格式化使用字符串格式化操作符即百分号%来实现.在%的左侧放置一个字符串(格式化字符串),而在右侧则放置希望格式化的值,可以使用一个值,如一个字符串或者数字,也可以使用多个值的元组或 ...