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

先看一个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. C#实现异步消息队列

    原文:C#实现异步消息队列 拿到新书<.net框架设计>,到手之后迅速读了好多,虽然这本书不像很多教程一样从头到尾系统的讲明一些知识,但是从项目实战角度告诉我们如何使用我们的知识,从这本书 ...

  2. Unity3D 如何图形问题修正旋转模型已导入?

     如何纠正旋转模型被导入? 一些立体艺术资源包导出其模式,以便 Z 轴向上.Unity 大多数标准的脚本中假定的三维世界 Y 轴代表了.在 Unity 比改动脚本使其契合easy得多. Z 轴朝上 ...

  3. mysql子查询慢的问题

      当你在用explain工具查看sql语句的运行计划时.若select_type 字段中出现"DEPENDENT SUBQUERY"时,你要注意了.你已经掉入了mysql子查询慢 ...

  4. React Native开发的通讯录应用

    React Native开发的通讯录应用(使用JavaScript开发原生iOS应用,vczero) 0.前言: 项目地址:https://github.com/vczero/React-Native ...

  5. SQL Server编程系列(2):SMO常用对象的有关操作

    原文:SQL Server编程系列(2):SMO常用对象的有关操作 在上一篇周公简单讲述了SMO的一些基本概念,实际上SMO体系结构远不止周公在上一篇中讲述的那么简单,下图是MSDN上给出的一个完整的 ...

  6. PHP连接Access数据库代码

    使用php的odbc函数,不创建数据源. $connstr="DRIVER=Microsoft Access Driver (*.mdb);DBQ=".realpath(" ...

  7. 熊猫猪新系统測试之三:iOS 8.0.2

    本来本猫要等到8.1版本号出来后再做測试的,结果等来等去就是迟迟不推送更新呀!说好10月20号的iOS 8.1呢?为了一鼓作气写完,就先不等了.先拿手头的iOS 8.0.2系统做一下測试吧! 8.x系 ...

  8. android屏蔽home键的实现

    Android中,网上很多屏蔽Home键都智能在4.0以下运行,在4.0以及以上运行直接崩溃. 需要这样更改(来源:http://androidmaster.iteye.com/): @Overrid ...

  9. 杭电dp题集,附链接还有解题报告!!!!!

    Robberies 点击打开链接 背包;第一次做的时候把概率当做背包(放大100000倍化为整数):在此范围内最多能抢多少钱  最脑残的是把总的概率以为是抢N家银行的概率之和- 把状态转移方程写成了f ...

  10. Socket 学习(三)

    前2节,说的是 Server 与 Client 的数据交互.服务端IP.端口固定,客户端 网服务端发送消息的时候,他的Socket对面被服务端获取到了,而且链接没有中断,他当然可以很容易回复信息. 现 ...