1. 程式人生 > >effective C++ 讀書筆記 條款11

effective C++ 讀書筆記 條款11

col tor 變量 pre amp 副本 swap 基本 目標

條款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