***************************************转载请注明出处: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. LINQ Enumerable 续 II

    Enumerable.TakeWhile和Enumerable.SkpWhile Enumerable.TakeWhile和Enumerable.SkpWhile将通过判断条件,来获取和跳过序列. T ...

  2. MySQL安装与测试

    工作室老师要求我们把MySQL装出来 今天折腾了下,本来不难的,不知道为什么用最新5.6.24的msi安装包,安装的时候选完路径后就没有后续了..蛋疼的我试了好几次,用cmd命令测试一直是 2003- ...

  3. \r \n有什么区别

    '\r'是回车,'\n'是换行,前者使光标到行首,后者使光标下移一格.通常用的Enter是两个加起来.下面转一篇文章. 回车和换行 今天,我总算搞清楚“回车”(carriage return)和“换行 ...

  4. 1105ecos笔记

    1 dbschema <?php$db['item']=array ( 'columns' => array ( 'item_id' => array ( 'type' => ...

  5. web前端知识

    4.表格与表单 4.1 动态添加行 <script language=”javascript”> window.onload=function(){ var oTr = document. ...

  6. python实现发工资脚本

    好开心啊,在旁边大神的帮助下,终于实现了发工资的python脚本,之前用shell写的老出错,刚才测试,发80个人工资详情,妥妥的,代码如下: from email.mime.multipart im ...

  7. Ftp协议Socket实现

    原来用WebRequest来传输文件,被人鄙视了.就弄个Socket版的,支持Active,Passive模式. 带事件日志,有时间的人可以拿去做C#版的flashfxp. public class ...

  8. HTML5 + CSS3 + JavaScript

    http://www.programmer.com.cn/14761/#more-14761 文/李晶 随着互联网产业的爆炸式增长,与之伴生的Web前端技术也在历经洗礼和蜕变.尤其是近几年随着移动终端 ...

  9. angularjs directive and component 指令与组件 ( 1.5.0 以后 )

    之前写过一篇了 http://www.cnblogs.com/keatkeat/p/3903673.html 但某些部分写的不太清楚,甚至有点错误,所以今天特地在这里再来谈谈. 这篇主要是说指令的隔离 ...

  10. MySql 到 SQL Server(MSSQL)

    我用 MySql 2年了,一直都是 asp.net + MySql 开发 为什么不用 MSSQL呢? 原因 : 在我的国家,几乎找不到任何一间托管公司有提供 SQL SERVER 的,有的话也是 20 ...