***************************************转载请注明出处: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的更多相关文章

  1. effective C++ 读书笔记 条款11

    条款11: 在operator= 中处理"自我赋值" 在实现operator=时考虑自我赋值是必要的就像 x=y .我们不知道变量x与y代表的值是否为同一个值(把x和y说成是一个指 ...

  2. Effective C++学习笔记 条款07:为多态基类声明virtual析构函数

    一.C++明确指出:当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未定义——实际执行时通常发生的是对象的 ...

  3. Effective C++学习笔记 条款06:如不想使用编译器自动生成的函数,就该明确拒绝

    一.为驳回编译器自动提供的机能,可将相应成员函数声明为private并且不予实现.(如果你仅仅是自己不实现的话,编译器会帮你实现) 如: class A { public: A(const strin ...

  4. Effective C++学习笔记 条款05:了解C++默默编写并调用的哪些函数

    一.如果用户没有提供构造函数.copy构造函数.copy assignment操作符和析构函数,当且仅当这些函数被需要的时候,编译器才会帮你创建出来.编译器生成的这些函数都是public且inline ...

  5. Effective C++学习笔记 条款04:确定对象被使用前已先被初始化

    一.为内置类型对象进行手工初始化,因为C++不保证初始化它们. 二.对象初始化数据成员是在进入构造函数用户编写代码前完成,要想对数据成员指定初始化值,那就必须使用初始化列表. class A { pu ...

  6. Effective C++学习笔记 条款02:尽量以const,enum,inline替换 #define

    尽量使用const替换 #define定义常量的原因: #define 不被视为语言的一部分 宏定义的常量,预处理器只是盲目的将宏名称替换为其的常量值,导致目标码中出现多分对应的常量,而const定义 ...

  7. Effective STL 学习笔记 32 ~ 33

    Effective STL 学习笔记 32 ~ 33 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...

  8. Effective STL 学习笔记: Item 22 ~ 24

    Effective STL 学习笔记: Item 22 ~ 24 */--> div.org-src-container { font-size: 85%; font-family: monos ...

  9. ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM - ROSMapModify - ROS地图修改

    ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM - 2 - MapModify地图修改 We can use gmapping model to genera ...

随机推荐

  1. 基于jQuery仿uploadify的HTML5图片上传控件jquery.html5uploader

    (function($){ var methods = { init:function(options){ return this.each(function(){ var $this = $(thi ...

  2. jQuery mini ui 2

    1.<a class="mini-button" iconCls="icon-add" onclick="addRow()" plai ...

  3. DHCP租约时间工作原理

    问题:    很多用户在使用路由器的DHCP服务器过程中都有一个疑问,DHCP有个设置项目是设置DHCP地址的租约时间,如果设置的比较短,是否会出现租约时间到了以后会重新去获取ip地址,造成用户断网? ...

  4. oracle 数据库开发面试题,当时笔试的时候一个没做出来,现附原题及答案

    1. ID123567810111215 表名tt,用sql找出ID列中不连续的ID,例如其中没有的4: --创建表及数据 CREATE TABLE tt(ID INTEGER); INSERT IN ...

  5. Entity Framework 的枚举类型

    新增数据模型,新增“实体”之后,新增“枚举类型”,创建Enum值,将“实体”中的列和Enum关联,选中“实体”中的列属性改变类型为Enum名称,生成数据库…… 如下转自:http://item.con ...

  6. 单点登录CAS使用记(八):使用maven的overlay实现无侵入的改造CAS

    前期在学习CAS部署的过程中,都是网上各种教程,各种方案不停的尝试. 期间各种侵入改源码,时间久了,改了哪个文件,改了哪段配置,增加了哪段代码,都有可能混淆不清了. 而且最大的问题是,万一换个人来维护 ...

  7. Linux 从 sar 到 sar2html 的认识

    这些变形的工具.诸如:淘宝的Tsar.ksar.sar2html....等.都是通过抓取 sar的数据   所以在最终呈现的数据上变化不大.只是展现的手段和效果不一样而已      sar 是帮助我们 ...

  8. 通过枚举enum实现单例设计

    一.枚举 通过enum关键字来实现枚举,在枚举中需要注意的有: 1. 枚举中的属性必须放在最前面,一般使用大写字母表示 2. 枚举中可以和java类一样定义方法 3. 枚举中的构造方法必须是私有的 通 ...

  9. linux笔记2.20

    用户相关:  /etc/passwd  用户信息 /etc/shadow  密码信息 /etc/group  组信息 添加用户:   useradd   -u -g 修改用户: usermod   - ...

  10. spring事务分类简述

    spring事务的传播行为是面试中经常被问到的问题,要将事务的传播行为与隔离级别熟练的掌握,在实际开发过程中,特别是在并发高.更新数据量大.关系表比较多的情况下,经常会遇到关于事务的问题.首先,要了解 ...