记住:

★确保当对象自我赋值时operator=有良好行为。有三种方法:比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap技术

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

------------------------------------------------------------------------------------

潜在的自我赋值举例:

a[i] = a[j];  //若i和j相同,便是自我赋值

*px = *py;  //若px和py恰巧指向同一个东西

这些潜在的自我赋值是别名(所谓别名就是有一个以上的方法指称某对象)带来的结果。实际两个对象只要来自于同一个继承体系,他们甚至不需要声明为相同类型就可能造成“别名”,∵一个base class的reference或pointer可以指向一个derived class对象。

举例:下面的operator=代码,表面合理,但自我赋值时不安全

 class Bitmap {...};
class Widget { ...
private:
Bitmap *pb; //含有指针或引用的类在写copying函数时就要注意!本能!
}; Widget& Widget::operator=( const Widget& rhs ) { delete pb; //停止使用当前的bitmap
pb = new Bitmap( *rhs.pb );
return *this;
}

上面存在的问题:*this和rhs有可能是同一个对象。这样delete就不只是销毁当前对象的bitmap,它也销毁rhs的bitmap。

解决方案一:比较“来源对象”和“目标对象”的地址(证同测试),经典解法,初级!!!

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

     if( this == &rhs )
return *this; //证同测试,是自我赋值的话就不做任何事 delete pb;
pb = new Bitmap( *rhs.pb );
return *this;
}

此版可行,但仍存在异常方面的麻烦:若new Bitmap导致异常(有可能因为分配时内存不足或因为Bitmap的copy constructor抛出异常),Widget最终会持有一个指针指向一块被删除的Bitmap。

解决方案二:手工排列语句顺序

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

     Bitmap *pOrig = pb;  //记住原先的pb
pb = new Bitmap( *rhs.pb );
delete pOrig;
return *this;
}

这段代码好处有二:

异常安全: 若new Bitmap失败,pb保持原状;

避免自我赋值:∵对原Bitmap做了一份复件、删除原Bitmap、再指向新制造的那个复件。

此种方法可能不是最高效的办法!!!但行得通。

解决方案三:使用copy-and-swap技术

 class Widget {

     ...
void swap( Widget &rhs ); //交换*this和rhs的数据,详见条款29
...
}; Widget& Widget::operator=( const Widget& rhs ) { Widget temp( rhs ); //为rhs数据制作一份复件---此即copy
swap( temp ); //将*this数据和上述复件的数据交换--此即swap
return *this;
}

方案三还有个改进版:

 Widget& Widget::operator=( Widget rhs ) { //注意这里是传值,∴rhs是被传对象的副本

     swap( rhs );        //将*this数据和上述复件的数据交换
return *this;
}

此版将copying动作从函数本体内移至函数参数构造阶段可令编译器有时生成更高效的代码

一个面试题目:写出String类的赋值运算符

class string{

    public:
string& operator=( string rhs ){ swap( rhs );
return *this;
} void swap( string& rhs ){ std::swap( _data, rhs._data );
} private:
char* _data;
}

EC读书笔记系列之6:条款11 在operator=中处理自我赋值的更多相关文章

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

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

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

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

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

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

  4. 11——在operator=中处理自我赋值

    在operator=函数中加一个测试: if(&rhs==this) copy and swap

  5. EC读书笔记系列之5:条款9、条款10

    条款9 绝不在构造和析构过程中调用virtual函数 记住: ★在构造和析构期间不要调用virtual函数,∵这类调用从不下降至derived class ---------------------- ...

  6. EC读书笔记系列之2:条款4 确定对象被使用前已先被初始化

    条款4:确定对象被使用前已先被初始化 记住: ★为内置对象进行手工初始化,因为C++不保证初始他们 ★构造函数最好使用初始化列表,而不要在构造函数本体内使用赋值操作.初始化列表列出的成员变量,其排列次 ...

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

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

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

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

  9. EC读书笔记系列之11:条款20、21

    条款20 宁以pass-by-reference-to-const替换pass-by-value 记住: ★尽量以pass-by-reference-to-const替换pass-by-value.前 ...

随机推荐

  1. oracle的内存管理(之中的一个)

    [深入解析oracle-eygle]学习笔记 1.内存管理 ORACLE数据库所使用的内存主要涉及到两个方面:PGA和SGA. 1.1 PGA管理 PGA指的是程序全局区(Program Global ...

  2. Hortonworks HDP Sandbox定制(配置)开机启动服务(组件)

    定制Hortonworks HDP开机启动服务能够这样做:本文原文出处: http://blog.csdn.net/bluishglc/article/details/42109253 严禁不论什么形 ...

  3. 【线段树求逆序数】【HDU1394】Minimum Inversion Number

    题目大意: 随机给你全排列中的一个,但不断的把第一个数丢到最后去,重复N次,形成了N个排列,问你这N个排列中逆序数最小为多少 做法: 逆序数裸的是N^2 利用线段树可以降到NlogN 具体方法是插入一 ...

  4. http头部信息研究

    1. Accept:告诉WEB服务器自己接受什么介质类型,*/* 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type. 2. Accept-Charset: 浏览器申明自 ...

  5. javascript设计模式——Publish/Subscribe

    推荐阅读http://dev.housetrip.com/2014/09/15/decoupling-javascript-apps-using-pub-sub-pattern/ 我们先引出问题的所在 ...

  6. UVA 246 10-20-30

    题意: 给52张的扑克堆,先从左往右发7张牌,之后连续不断从左往右发7张牌,如果有牌堆形成了以下3种情况(按顺序判断):1.头两张+尾一张和为10或20或30.2.头一张+尾两张和为10或20或30. ...

  7. UILabel头文件常见属性

    text : default is nil 文本属性,默认值是 nil @property(nullable, nonatomic,copy) NSString *text; font : defau ...

  8. 如何获取浏览器URL中查询字符串的参数

    首先要知道Location这个对象以及这个对象中的一些属性: href:设置或返回完整的url.如本博客首页返回http://www.cnblogs.com/wymninja/ host:设置或返回主 ...

  9. switch 与 whille相互套用

    一直自以为还比较了解C++,这两天写个小工具结果出现了个bug,查了几个小时.现在才发现我这么水. switch是C++后来推出了,目的在于提高代码结构清晰度. 但是switch与while连用时是有 ...

  10. [jQuery] jQuery如何获取同一个类标签的所有的值

    碰巧在开发的时候遇到这个问题,因为jQuery总是只返回第一个类标签的值,所以无法达到我们的要求. 比如: var btn = jQuery('.btn').val(); 获取的只是第一个类标签为bt ...