《Effective C++ 》学习笔记——条款11
***************************************转载请注明出处: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的更多相关文章
- effective C++ 读书笔记 条款11
条款11: 在operator= 中处理"自我赋值" 在实现operator=时考虑自我赋值是必要的就像 x=y .我们不知道变量x与y代表的值是否为同一个值(把x和y说成是一个指 ...
- Effective C++学习笔记 条款07:为多态基类声明virtual析构函数
一.C++明确指出:当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未定义——实际执行时通常发生的是对象的 ...
- Effective C++学习笔记 条款06:如不想使用编译器自动生成的函数,就该明确拒绝
一.为驳回编译器自动提供的机能,可将相应成员函数声明为private并且不予实现.(如果你仅仅是自己不实现的话,编译器会帮你实现) 如: class A { public: A(const strin ...
- Effective C++学习笔记 条款05:了解C++默默编写并调用的哪些函数
一.如果用户没有提供构造函数.copy构造函数.copy assignment操作符和析构函数,当且仅当这些函数被需要的时候,编译器才会帮你创建出来.编译器生成的这些函数都是public且inline ...
- Effective C++学习笔记 条款04:确定对象被使用前已先被初始化
一.为内置类型对象进行手工初始化,因为C++不保证初始化它们. 二.对象初始化数据成员是在进入构造函数用户编写代码前完成,要想对数据成员指定初始化值,那就必须使用初始化列表. class A { pu ...
- Effective C++学习笔记 条款02:尽量以const,enum,inline替换 #define
尽量使用const替换 #define定义常量的原因: #define 不被视为语言的一部分 宏定义的常量,预处理器只是盲目的将宏名称替换为其的常量值,导致目标码中出现多分对应的常量,而const定义 ...
- Effective STL 学习笔记 32 ~ 33
Effective STL 学习笔记 32 ~ 33 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...
- Effective STL 学习笔记: Item 22 ~ 24
Effective STL 学习笔记: Item 22 ~ 24 */--> div.org-src-container { font-size: 85%; font-family: monos ...
- ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM - ROSMapModify - ROS地图修改
ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM - 2 - MapModify地图修改 We can use gmapping model to genera ...
随机推荐
- MVC4 EF linq从客户端中检测到有潜在的危险的Request.Path值
今天做项目的时候遇到了这样的问题贴出来给大家分享下啦, 使用MVC4 EF linq跳转视图的时候出现,从客户端中检测到有潜在的危险的Request.Path值错误,如下图所示: 解决办法如下: r ...
- repeater 结合checkbox批量删除
项目中用到这个,从网上搜了搜相关内容,代码如下 <script type="text/javascript"> function checkAllThis(obj) { ...
- 使用URL读取网络图片资源
URL(Uniform Resource Locator) 对象代表统一资源定位器. 代码如下: public class MainActivity extends ActionBarActivity ...
- HTML5 学习
1.<header> 标签定义文档的页眉(介绍信息) 标签是 HTML 5 中的新标签 <header> <h1>Welcome to my homepage< ...
- rsync从windows到linux的同步备份
名称 角色 IP地址 Windows server 2003 服务器 Eth0:192.168.1.1 RHEL5.5 客户端 Eth0:192.168.1.2 一.cwRsyncServer服务 ...
- Undefined symbols for architecture x86_64:
真机运行正常, 但要在模拟器运行的时候, 编译就报错了: 解决方法: 1.将Build Settings的Architectures修改为arm7 armv7s.Xcode7默认是加上arm64的,但 ...
- java数据流
DataInputStream和DataOutputStream提供了可以直接存取java基本类型(int,double等)的方法.对于存取基本类型,在效率上比普通字节流要快很多.它们分别继承inpu ...
- S_OK与S_FALSE,E_FAIL
S_OK是COM服务器返回正确 S_FALSE是COM服务器返回错误,不过这个错误是可以不处理的,不影响程序正常运行.只是结果不是想要的 E_FAIL是必须处理的错误. //// Success co ...
- ECSTORE 关于前台页面DIALOG的调用
在需调用dialog的html页面中插入本段代码. link='<{link app=test ctl=site_test act=abc}>'; var dialog = new Dia ...
- C++实现Log()日志函数
转载请注明原创:http://www.cnblogs.com/StartoverX/p/4600649.html 需求:Log()函数,能够自动根据时间记录日志信息,要求不定参数类型和参数个数. 第一 ...