问题聚焦:
自我赋值看似有点愚蠢的行为,其实总会发生的
首先:它是合法的,
其次,它不一定是安全的,
再次,它有时候不是那么明显。

先看一个Demo


class Widget { ... };
Widget w;
...
/** 最明显的自我赋值 **/
w = w; /** 不那么明显的自我赋值 **/
// 在某个地方实现了i = j或者相同作用的事情
a[i] = a[j] /** 潜在的自我赋值 **/
*px = *py; /** 更为隐蔽的自我赋值“别名” **/
class Base { ... };
class Derived : public Base { ... };
void doSomething( const Base& rb, Derived* pd); // rb 和 *pd可能是同一对象

一般而言,如果某段代码操作指针和引用,而它们被用来指向多个相同类型的对象,就需要考虑这些对象是否为同一个了。
自我赋值可能带来的两种潜在的危险:
  • 自我赋值安全性
  • 异常安全
来看下面的例子:

class Bitmap { ... };
class Widget {
...
private:
Bitmap* pd;
}; /** operator=的代码实现 **/
Widget&
Widget::operator=(const Widget& rhs)
{
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}

自我赋值安全性:

若rhs和当前对象是同一对象,那么在销毁当前对象的pb时,把rhs的对象也销毁了。

改进:认同测试


/** operator=的代码实现 **/
Widget&
Widget::operator=(const Widget& rhs)
{
if (this == &rhs) return *this; // 认同测试 delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}

上述改进后的代码避免了自我赋值安全性问题。
我们来关注一下第二个问题
异常安全性:
如果new Bitmap()发生异常,那么结果就是pb赋值直白,Widget最终持有一个指针指向一块被删除的Bitmap。

改进一:精心安排语句


/** operator=的代码实现 **/
Widget&
Widget::operator=(const Widget& rhs)
{
Bitmap* pOrig = pb;
pb = new Bitmap(*rhs.pb); // 如果new Bitmap抛出异常,pb保持原状
delete pOrig;
return *this;
}

改进方案二:copy and swap

class Widget {
...
void swap(Widget& rhs);
...
}; Widget& Widget::operator=(const Wdiget& rhs)
{
Widget temp(rhs);
swap(temp);
return *this;
}

思想:
拷贝构造函数要声明为“按值传递”
按值传递会造成一份副本
小结:

确保当对象自我赋值时operator=有良好的行为。

包括:

对象来源

目标对象地址

语句顺序

确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。

参考资料:
《Effective C++ 3rd》

Effective C++(11) 自我赋值(a=a)时会发生什么?的更多相关文章

  1. 读书笔记 effective c++ Item 11 在operator=中处理自我赋值

    1.自我赋值是如何发生的 当一个对象委派给自己的时候,自我赋值就会发生: class Widget { ... }; Widget w; ... w = w; // assignment to sel ...

  2. Effective C++ 条款11,12 在operator= 中处理“自我赋值” || 复制对象时不要忘记每一个成分

    1.潜在的自我赋值     a[i] = a[j];     *px = *py; 当两个对象来自同一个继承体系时,他们甚至不需要声明为相同类型就可能造成别名. 现在担心的问题是:假如指向同一个对象, ...

  3. Effective C++ -----条款11: 在operator=中处理“自我赋值”

    确保当对象自我赋值时operator=有良好行为.其中技术包括比较“来源 对象”和“目标对象”的地址.精心周到的语句顺序.以及copy-and-swap. 确定任何函数如果操作一个以上的对象,而其中多 ...

  4. Effective C++ 条款11:在operator=中处理"自我赋值"

    "自我赋值"发生在对象被赋值给自己时: class Widget { ... }; Widget w; ... w = w; // 赋值给自己 a[i] = a[j]; // 潜在 ...

  5. Effective C++_笔记_条款11_在operator=中处理“自我赋值”

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为什么会出现自我赋值呢?不明显的自我赋值,是“别名”带来的结果: ...

  6. 条款11:在operator=中处理“自我赋值”

    什么是自我赋值,就是 v = v 这种类型的语句,也许很多人都会说鄙视这种写法,但是如下的写法会不会出现呢? 比如:a[i] = a[j];      // 不巧的是i可能和j相等 *px = *py ...

  7. 【11】在operator=中处理“自我赋值”

    1.自我赋值,看起来愚蠢,但是却合法.有些自我赋值一眼就可看出来.有些自我赋值是潜在的.比如:a[i] = a[j]; *px = *py; 甚至不同类型的指针,都指向同一个地址,也是自我赋值,这一类 ...

  8. [Effective C++ --011]在operator=中处理“自我赋值”

    一.何谓“自我赋值”? 1.1.场合一 直接赋值 w = w; 1.2.场合二 同一数组         a[i] = a[j]: 1.3.场合三 指针         *px = *py: 1.4. ...

  9. EC读书笔记系列之6:条款11 在operator=中处理自我赋值

    记住: ★确保当对象自我赋值时operator=有良好行为.有三种方法:比较“来源对象”和“目标对象”的地址.精心周到的语句顺序.以及copy-and-swap技术 ★确定任何函数若操作一个以上对象, ...

随机推荐

  1. Php面向对象 – 继承和重写

    Php面向对象 – 继承和重写 承受: php于,通过类.使用特殊的经营宗旨. 通过定义类,采用extends来表示当前的类对象继承该类的对象. 样例: class C { public  $p_c  ...

  2. 使用ExpandableListView时间轴效果达到

    不废话,首先在地图上,查看结果 这是用ExpandableListView来实现时间轴效果,原理比較简单,以月份为第一级,以天为第二级来实现的. package com.hj.main; import ...

  3. Android开发之自己主动登录功能的实现

    在我们平时使用的手机应用都能够实现仅仅须要登陆一次账号后,第二次进入应用直接跳转到效果界面的效果,还有QQ的登陆框是怎样记忆我们的隐身登陆,保存账号选项的呢,这些都是通过使用SharedPrefere ...

  4. hdu 5066 Harry And Physical Teacher(Bestcoder Round #14)

    Harry And Physical Teacher Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Ja ...

  5. SlidingMenu 左侧滑动菜单

    1.MainActivity package loveworld.slidingmenu; import java.util.ArrayList; import android.app.Activit ...

  6. php 开发技巧

    以下九种PHP一个非常有用的功能.我不知道你还没有使用?1. 的功能,你可能知道的参数,任意数量PHP我同意你定义一个函数默认参数. 但你可能并不知道PHP还同意你定义一个全然随意的參数的函数以下是一 ...

  7. hdu Just a Hook

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1698 线段树+lazy操作     线段树是从上到下开始建树,树状数组是从下到上建树.... 代码: ...

  8. Java 递归算法

    其基本思路是递归算法设计:对于一个复杂的问题,原问题分为几个子问题相似相对简单.继续下去,直到孩子可以简单地解决问题,这是导出复发,因此,有复发的原始问题已经解决. 关键是要抓住: (1)递归出口 ( ...

  9. HDU4405-Aeroplane chess(可能性DP需求预期)

    Aeroplane chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  10. DeviceIOControl具体解释-各个击破

    DeviceIoControl这个api我们用的不多,可是非常重要,有时会帮助我们实现一些特别的需求, 如获取硬件设备信息.与硬件设备通信(读写数据)等,对比msdn,以下我们详解一下这个api的使用 ...