(整理自Effctive C++,转载请注明。整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/

为什么会出现自我赋值呢?不明显的自我赋值,是“别名”带来的结果:所谓“别名”就是“有一个以上的方法指涉对象”。一般而言如果某段代码操作pointers或references而它们被用来“指向多个相同类型的对象”,就需要考虑这些对象是否为同一个。实际上两个对象来自同一个继承体系,它们甚至不需要声明为相同类型就可能造成“别名”。因为一个base class的reference或pointer可以指向一个derived class对象。如果你尝试自行管理资源,可能会掉进“在停止使用资源之前意外释放了它”的陷阱。假设你建立一个class用来保存一个指针指向一块动态分配的位图(bitmap):

   1: class Bitmap{...};

   2: class Widget{

   3:     ...

   4:     private:

   5:         Bitmap* pb ;

   6: };

下面是operator=的实现代码:

   1: Widget&

   2: Widget::operator=(const Widget& rhs)

   3: {

   4:     delete pb ;                  //停止使用当前的bitmap

   5:     pb = new Bitmap (*rhs.pb) ;  //使用rhs的bitmap的副本

   6:     return *this ;                //返回当前对象的引用

   7: }

这份代码表面上合理,但自我赋值时并不安全。operator=函数内的*this(赋值的目的端)和rhs有可能是同一个对象。果真如此delete就不只销毁当前对象的bitmap,它也销毁rhs的bitmap。在函数的末尾,Widget—它原本不该被自我赋值动作改变的—发现自己持有一个指针指向一个已被删除的对象。

欲阻止这种错误,可以在operator=最前面增加一个“正同测试”(identity test)达到“自我赋值”的检验目的:

   1: Widget& Widget::operator=(const Widget& rhs)

   2: {

   3:     if(this==&rhs) return *this ;      //正同测试:如果是自我赋值,直接返回当前对象

   4:     

   5:     delete pb ;

   6:     pb = new Bitmap( *rhs.pb );

   7:     return *this ;

   8: }

这个版本具备“自我赋值安全性”,但是仍然存在异常方面的麻烦。更明确地说,如果“new Bitmap”导致异常,Widget最终会持有一个指针指向一块被删除的Bitmap。

令人高兴的是,让operator=具备“异常安全性”往往自动获得“自我赋值安全性”的回报。许多时候一群精心安排的语句就可以导出异常安全的代码。例如以下代码,我们只需注意在赋值pb之前别删除pb:

   1: Widget& Widget::operator=(const Widget& rhs)

   2: {

   3:     Bitmap* pOrig = pb ;              //记住原先的pb

   4:     pb = new Bitmap( *rhs.pb ) ;      //令pb指向*pb的一个复件

   5:     delete pOrig ;                    //删除原来的pb

   6:     return *this ; 

   7: }

现在,如果“new Bitmap”抛出异常,pb保持原状。

在operator=函数内手工排列语句的一个替代方案是,使用所谓的copy和swap技术:

   1: class Widget{

   2: ...

   3: void swap(Widget& rhs);       //交换*this和rhs的数据

   4: ...

   5: };

   6: Widget& Widget::operator=(const Widget& rhs)

   7: {

   8:     Widget temp(rhs);  //为rhs的数据制作一个副本

   9:     swap(temp);        //将*this数据和上述复件的数据交换

  10:     return *this;

  11: }

请注意:

(1)确保当对象自我赋值时operator=有良好行为。其技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap。

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

Effective C++_笔记_条款11_在operator=中处理“自我赋值”的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. EC笔记:第二部分:11:在operator=中处理“自我赋值”

    已经一年半没有写过博客了,最近发现学过的知识还是需要整理一下,为知笔记,要开始收费了以前写在为知笔记上笔记也会慢慢的转到博客里. 话不多说,进入正题. 考虑考虑以下场景: 当某个对象对自身赋值时,会出 ...

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

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

  9. 条款十七: 在operator=中检查给自己赋值的情况

    在赋值运算符中要特别注意可能出现别名的情况,其理由基于两点.其中之一是效率.如果可以在赋值运算符函数体的首部检测到是给自己赋值,就可以立即返回,从而可以节省大量的工作,否则必须去实现整个赋值操作. 另 ...

随机推荐

  1. hdu 4784 Dinner Coming Soon

    spfa+优先队列.刚开始只用的spfa,结果tle到死.然后听队友说要用到优先队列,想了想,对时间分层的话的确每一个结点都只进队列一次即可,因为只有大时间才能更新出小时间,然后就wa成shi了.按队 ...

  2. POJ1273 最大流 EK算法

    套了个EK的模板 //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdi ...

  3. 创建出多个app

    修改红线里的内容

  4. SolrCloud Hello Word

    Solr Cloud 设计出来的目的是使你的搜索服务具有更高的可用性,提高容错.容灾能力.下面我们在一台电脑上建立2个solr服务,作为一个solrCloud分片(shard),初步认识一下solrC ...

  5. C++中的智能指针(auto_ptr)

    实际上auto_ptr 仅仅是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势.使用它不必每次都手动调用delete去释放内存.当然有利也有弊,也不是全然完美的. 本 ...

  6. E. Riding in a Lift(Codeforces Round #274)

    E. Riding in a Lift time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  7. Android SurfaceView实战 带你玩转flabby bird (上)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/42965779 ,本文出自:[张鸿洋的博客] 1.概述 哈,记得以前写过Andro ...

  8. 举例android项目中的string.xml出现这个The character reference must end with the ';' delimiter.错误提示的原因及解决办法

    今天在一个android项目中的string.xml中写这样一个字符串时出现了下面这个错误提示: The reference to entity "说明" must end wit ...

  9. 在C++中使用C#编写的类2

    在那篇<在C#中使用C++编写的类>中我介绍了如何在C#中使用C++编写的类.可是由于C#在用户界面设计.数据库存储和XML文件读取等方面的优势,有时候也会出现要在C++中使用C#编写的类 ...

  10. Android 去掉Activity的跳转动画

    startActivity或finish的时候调用一句话即可: overridePendingTransition(0, 0);