***************************************转载请注明出处: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. MVC4 EF linq从客户端中检测到有潜在的危险的Request.Path值

    今天做项目的时候遇到了这样的问题贴出来给大家分享下啦, 使用MVC4 EF linq跳转视图的时候出现,从客户端中检测到有潜在的危险的Request.Path值错误,如下图所示: 解决办法如下:  r ...

  2. repeater 结合checkbox批量删除

    项目中用到这个,从网上搜了搜相关内容,代码如下 <script type="text/javascript"> function checkAllThis(obj) { ...

  3. 使用URL读取网络图片资源

    URL(Uniform Resource Locator) 对象代表统一资源定位器. 代码如下: public class MainActivity extends ActionBarActivity ...

  4. HTML5 学习

    1.<header> 标签定义文档的页眉(介绍信息) 标签是 HTML 5 中的新标签 <header> <h1>Welcome to my homepage< ...

  5. rsync从windows到linux的同步备份

    名称 角色 IP地址 Windows server 2003 服务器 Eth0:192.168.1.1 RHEL5.5 客户端 Eth0:192.168.1.2   一.cwRsyncServer服务 ...

  6. Undefined symbols for architecture x86_64:

    真机运行正常, 但要在模拟器运行的时候, 编译就报错了: 解决方法: 1.将Build Settings的Architectures修改为arm7 armv7s.Xcode7默认是加上arm64的,但 ...

  7. java数据流

    DataInputStream和DataOutputStream提供了可以直接存取java基本类型(int,double等)的方法.对于存取基本类型,在效率上比普通字节流要快很多.它们分别继承inpu ...

  8. S_OK与S_FALSE,E_FAIL

    S_OK是COM服务器返回正确 S_FALSE是COM服务器返回错误,不过这个错误是可以不处理的,不影响程序正常运行.只是结果不是想要的 E_FAIL是必须处理的错误. //// Success co ...

  9. ECSTORE 关于前台页面DIALOG的调用

    在需调用dialog的html页面中插入本段代码. link='<{link app=test ctl=site_test act=abc}>'; var dialog = new Dia ...

  10. C++实现Log()日志函数

    转载请注明原创:http://www.cnblogs.com/StartoverX/p/4600649.html 需求:Log()函数,能够自动根据时间记录日志信息,要求不定参数类型和参数个数. 第一 ...