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

在实现operator=时考虑自我赋值是必要的就像 x=y 。我们不知道变量x与y代表的值是否为同一个值(把x和y说成是一个指针更恰当一点)。

例如以下

第一版:

#include <iostream>

using namespace std;

class bitmap
{
public:
bitmap()
{
cout<<"调用bitmap()无參构造函数"<<endl;
}
bitmap(const bitmap& bt)
{
this->i = bt.i;
cout<<"调用bitmap()拷贝构造函数"<<endl;
}
~bitmap()
{
}
private:
int i;
};
class Widget
{
public:
Widget()
{
pb = new bitmap();
}
Widget(const Widget& wd)
{
this->pb = wd.pb;
}
public:
Widget& operator=(const Widget& rhs);
private:
bitmap* pb; //定义一个从heap分配而得的对象
}; //第一版赋值函数:
Widget& Widget::operator=(const Widget& rhs)
{
delete pb;
pb = new bitmap(*rhs.pb);
return *this;
}
//这一版函数的pb在使用前清理掉之前的pb指向。再接受一个new出来的新对象,看着非常顺理成章,可是
//当this与函数參数rhs相等的时候,pb = new bitmap(*rhs.pb);由于我们已经把*rhs.pb delete掉了。 int main()
{ Widget w1;
Widget w2;
w1 = w2;
return 0;
}
/*
调用bitmap()无參构造函数
调用bitmap()无參构造函数
调用bitmap()拷贝构造函数
Press any key to continue
*/

第二版:

//第二版赋值函数:
Widget& Widget::operator=(const Widget& rhs)
{
if (this == &rhs)
{
return *this;
} delete pb;
pb = new bitmap(*rhs.pb);
return *this;
}
//这个版本号行的通,赋值函数基本上是能够接受的,可是不见得是安全的,由于当new产生异常时pb依旧是一个
//不确定的指针。

第三版:

//第三版赋值函数:
Widget& Widget::operator=(const Widget& rhs)
{
bitmap *pOrig = pb;
pb = new bitmap(*rhs.pb);
delete pOrig;
return *this;
}
//第三版函数在開始的时候用pOrig记录了pb。当new没有异常时我们再把pb原来的指向空间释放掉
//从而提高了安全性。这样的方法也相同可以处理自我赋值。假如这里rhs=*this。我们先对原来的
//bitmap做了一份备份,删除原bitmap后,指向了我们的那一份备份,也许这样的处理自我赋值的方法
//不是非常好。可是行的通,在保证安全性的情况下採用这样的办法非常不错。

第四版:

#include <iostream>

using namespace std;

class bitmap
{
public:
bitmap()
{
cout<<"调用bitmap()无參构造函数"<<endl;
}
bitmap(const bitmap& bt)
{
this->i = bt.i;
cout<<"调用bitmap()拷贝构造函数"<<endl;
}
~bitmap()
{
}
private:
int i;
};
class Widget
{
public:
Widget()
{
cout<<"调用Widget()无參构造函数"<<endl;
pb = new bitmap();
}
Widget(const Widget& wd)
{
cout<<"调用Widget()拷贝參构造函数"<<endl;
this->pb = wd.pb;
}
void my_swap(Widget& rhs);
public:
Widget& operator=(const Widget& rhs);
private:
bitmap* pb; //定义一个从heap分配而得的对象
}; //第四版赋值函数: void Widget::my_swap( Widget& rhs)
{
pb = rhs.pb;
} Widget& Widget::operator=(const Widget& rhs)
{
Widget temp(rhs);//防止改变rhs
my_swap(temp);
return*this;
}
//第四版赋值函数利用的是copy and swap技术,这个技术在条款29其中
//有具体说明。还没认真看,这里就不解释了。 //第四版也能够这样用:
Widget& Widget::operator=(Widget rhs)
{
my_swap(rhs); //事实上本质上是一样的,由于传递的參数是值传递,所以这里传递的是rhs的一个副本。相当于Widget temp(rhs);主要就是防止rhs被改变。
return*this;
} int main()
{ Widget w1;
Widget w2;
w1 = w2;
return 0;
}
/*
调用Widget()无參构造函数
调用bitmap()无參构造函数
调用Widget()无參构造函数
调用bitmap()无參构造函数
调用Widget()拷贝參构造函数
Press any key to continue
*/

总结:

1:确保当对象自我赋值时 operator= 有良好行为,当中技术包含比較“原来对象”和“目标对象”的地址。、精心周到的语句顺序,以及copy and swap

2:确定不论什么函数假设操作一个以上的对象,而当中多个对象是同一个对象时,其行为仍然正确。

effective C++ 读书笔记 条款11的更多相关文章

  1. effective C++ 读书笔记 条款08

    条款08  别让异常逃离析构函数: 假设在析构函数其中发生了异常,程序可能会过早结束或者导致不明白行为(异常从析构函数传播出去) 看代码: #include <iostream> usin ...

  2. effective C++ 读书笔记 条款14 以对象管理资源

    如果我们使用一个投资行为的程序库: #include "stdafx.h" #include <iostream> #include <memory> us ...

  3. Effective STL 读书笔记

    Effective STL 读书笔记 标签(空格分隔): 未分类 慎重选择容器类型 标准STL序列容器: vector.string.deque和list(双向列表). 标准STL管理容器: set. ...

  4. Effective STL读书笔记

    Effective STL 读书笔记 本篇文字用于总结在阅读<Effective STL>时的笔记心得,只记录书上描写的,但自己尚未熟练掌握的知识点,不记录通用.常识类的知识点. STL按 ...

  5. 《Effective C++》读书笔记 条款02 尽量以const,enum,inline替换#define

    Effective C++在此条款中总结出两个结论 1.对于单纯常量,最好以const对象或enum替换#define 2.对于形似函数的宏,最好改用inline函数替换#define 接下来我们进行 ...

  6. effective c++读书笔记(一)

    很早之前就听过这本书,找工作之前读一读.看了几页,个人感觉实在是生涩难懂,非常不符合中国人的思维方式.之前也有博主做过笔记,我来补充一些自己的理解. 我看有人记了笔记,还不错:http://www.3 ...

  7. Effective Java读书笔记完结啦

    Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...

  8. Effective C++读书笔记(转)

    第一部分 让自己习惯C++ 条款01:视C++为一个语言联邦 一.要点 ■ c++高效编程守则视状况而变化,取决于你使用c++的哪一部分. 二.扩展 将c++视为一个由相关语言组成的联邦而非单一语言会 ...

  9. 《Effective C++ 》学习笔记——条款11

    ***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...

随机推荐

  1. Java系列学习(八)-继承

    1.代码块 (1)在java中,使用 { } 括起来的代码 被称为代码块 (2)分类: A:局部代码块 [局部位置] [作用:用于限定 变量的生命周期] B:构造代码块 [在类中的成员位置,用{}括起 ...

  2. HDU3949 XOR(线性基第k小)

    Problem Description XOR is a kind of bit operator, we define that as follow: for two binary base num ...

  3. SAS学习笔记之《SAS编程与数据挖掘商业案例》(4)DATA步循环与控制、常用全程语句、输出控制

    SAS学习笔记之<SAS编程与数据挖掘商业案例>(4)DATA步循环与控制.常用全程语句.输出控制 1. 各种循环与控制 DO组 创建一个执行语句块 DO循环 根据下标变量重复执行DO和E ...

  4. Java&Xml教程(二)使用DOM方式解析XML文件

    DOM XML 解析方式是最容易理解的,它將XML文件作为Document对象读取到内存中,然后你可以轻松地遍历不同的元素和节点对象.遍历元素和节点不需要按照顺序进行. DOM解析方式适合尺寸较小的X ...

  5. Android popupwindow和dialog监听返回键

    使用情况: 在activity中,出现了popupwindow和dialog,这个时候,如果点击返回键,它们消失了,但是一些操作还在继续.如:1.进行耗时操作,出现dialog提醒用户等待,这时,按下 ...

  6. Json——转义符

    C#后台直接输出Json字符串需要反斜杠“\” context.Response.Write("[{\"Name\": \"wqx\", \" ...

  7. 通过offset值的设置使html元素对齐

    今天是我第一次写这个随笔,为了记录我发现的一个jquery的offset的值的问题. 这个offset的值会因为页面标签是否处于隐藏状态而表现出不同的值,隐藏状态时,offset的值是相对于直接父亲的 ...

  8. Review:Microbiota, metagenome, microbiome傻傻分不清

    Microbiota 微生物群   微生物群是指研究动植物体上共生或病理的微生物生态群体.微生物群包括细菌.古菌.原生动物.真菌和病毒.研究表明其在宿主的免疫.代谢和激素等方面非常重要.近义词Micr ...

  9. CI框架3.x 之实现前后端分离

    一.建立合理的目录结构 admin与home为后台和前台的控制器和模板文件夹 二.定义前后台视图路径常量 在constants.php中添加如下代码: //定义前台视图路径常量 define('HOM ...

  10. /etc目录常用配置文件

    /etc/resolv.conf DNS客户端配置文件,逐渐被网卡配置文件所替代 /etc/hosts 本机DNS解析文件,优先级高于DNS服务器 /etc/hostname CentOS 7 主机名 ...