effective C++ 读书笔记 条款11

条款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:确定不论什么函数假设操作一个以上的对象,而当中多个对象是同一个对象时,其行为仍然正确。

时间: 2024-11-06 15:05:41

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

effective C++ 读书笔记 条款06

条款06:若不想使用编译器自动生成的函数,就该明确拒绝: 直接看代码与注释: #include <iostream> using namespace std; class Test { public: Test() { } ~Test() { } /* void TT() { Test t1; Test t2(t1); } */ private: Test(const Test& test); Test& operator = (const Test& test); }

Effective C++读书笔记(条款11-17)

继续上一篇... (二).构造/析构/赋值运算 ____________________________________________________________________________________________________________________________________ 条款11:在operator= 中处理 "自我赋值" #1.确保当对象自我赋值时 operator=有良好行为.其中包括"自我赋值安全性"和 "异

Effective C++读书笔记(条款18-23)

(四).设计与声明 ____________________________________________________________________________________________________________________________________ 条款18:让接口容易被使用,而不容易被误用 #1.导入新类型可以让接口不易被误用,以函数替换对象则可以保证类型安全性. 例如: class Date{ public: Date(int month, int day

Effective C++读书笔记(条款24-29)

Effective C++第四篇,扩展的有点多... (四).设计与声明 ____________________________________________________________________________________________________________________________________ 条款24:若所有参数皆需类型转换,请为此采用non-member函数 #1.如果你需要为某个函数的所有参数(包括被 this指针所指的那个隐喻参数)进行 类型转

Effective C++读书笔记(条款1-10)

不得不说,Effective C++确实是一本C++进阶的好书,刚浏览完第二遍, 现对其做一个大体性的总结 ,并进行适当的展开,作为以后C++参考复习之用. (一).让自己习惯C++ ____________________________________________________________________________________________________________________________________ 条款1:视C++为一个语言联邦 #1.将C++ 分

effective C++ 读书笔记 条款21

条款21 :必须返回对象时,别妄想返回其reference 条款20里面虽然说传引用比传值好用,但是不能传递一些 reference指向其实并不存在的对象 上代码: #include <iostream> using namespace std; class Rational { public: // Rational() // { // } Rational(int m = 0, int n = 0 ) { } ~Rational() { } private: int n, d; /* 运算

effective C++ 读书笔记 条款20

条款20:宁以 pass-by-reference-to-const 替换 pass -by -value 1:采用后者效率高:看代码: #include <iostream> using namespace std; class Person { public: Person() { cout<<"Person()"<<endl; } Person(const Person& p) { cout<<"Person(co

effective C++ 读书笔记 条款08

条款08  别让异常逃离析构函数: 假设在析构函数其中发生了异常,程序可能会过早结束或者导致不明白行为(异常从析构函数传播出去) 看代码: #include <iostream> using namespace std; class DBConnection { public: void close() { int i = 3; int j = 0; int k = i/j; printf("%d\n",k); } }; class DBConn { public: DBC

effective C++ 读书笔记 条款12与条款13

条款12:确定你的public继承塑膜出is-a关系: 这个条款主要将了一些特殊情况:比如企鹅是鸟,企鹅可以继承于鸟,但是鸟会飞,企鹅却不能飞:还有让正方形继承矩形可能也会造成这种尴尬! 这个问题以前想过,但是不知道怎么解决,如果现实生活当中确实要这么使用:比如 猫 狗 鱼  猪等等许多动物继承Animal类,但是猫狗等不会游泳, 假如这里是有很多动物,不能采用鱼里面专门加一个方法!  这个现在还没想出来,条款12也没有讲如果要这么用该怎么处理就是将要避免这样. is - a; 在面向对象程序设