題目: 如下為類型CMyString的聲明,請為該類型添加賦值運算符函數.


賦值運算符函數
1.題目:
    如下為類型CMyString的聲明,請為該類型添加賦值運算符函數.
class CMyString
{
public:
	CMyString(char* pData = NULL);
	CMyString(const CMyString& str);
	~CMyString(void);
private:
	char* m_pData;
};

在定義一個賦值運算符函數時,主要是在考察以下幾點.
    1.是否把返回值的類型聲明為該類型的引用,並在該函數結束前返回實例自身的引用(即*this),只有返回一個引用,才可以允許連續賦值。否則如果函數的返回值是void,引用該賦值運算符將不能做連續賦值。假設有三個CMyString的對象:str1,str2,str3,在程序中語句str1 = str2 = str3.
    2.是否把傳入的參數的類型聲明為常量引用。如果傳入的參數不是引用而是實例,那么從形參到實參就會調用一次復制構造函數。把參數聲明為引用就可以避免這樣的無謂消耗,提高代碼的效率。同時我們在賦值運算符函數內不會改變傳入的實例的狀態,因此應該為傳入的應用參數加上const關鍵字。
    3.是否釋放實例自己本身的內存。如果我們忘記在分配內存之前釋放自身已有的空間,程序將出現內存泄露。
    4.是否判斷傳入的參數和當前的實例(*this)是不是同一個實例。如果是同一個,則不進行賦值操作,直接返回。如果事先不判斷就進行賦值,那么在釋放實例自身的內存時就會導致嚴重的問題:當*this和傳進來的參數是同一個實例時,那么一旦釋放了自身的內存,傳入的參數的內存也同時被釋放了,因此再也找不到需要賦值的內容了。

#include<iostream>
#include<string.h>
using namespace std;


class CMyString
{
public:
	CMyString(char* pData = NULL);
	CMyString(const CMyString& str);
	CMyString& operator=(const CMyString &str);
	~CMyString(void);
private:
	char *m_pData;
};
CMyString& CMyString::operator=(const CMyString &str)
{
	if(this == &str)
		return *this;
	
	delete []m_pData;
	m_pData = NULL;

	m_pData = new char[strlen(str.m_pData) + 1];
	strcpy(m_pData,str.m_pData);

	return *this;
}

int main()
{
	CMyString str("string");
	CMyString str1("qwerty");
	str1 = str;

	return 0;
}
這是一般教材上所提供的參考代碼,如果接受面試的是應屆畢業生的話或者C++初級程序員,能全面的考慮到前面四點並且完整的寫出代碼,面試官可能會讓他通過這輪面試。如果是C++高級程序員,面試官可能會提出更高的要求。
    在之前的函數中,我們在分配內存之前先用delete函數釋放了m_pData的內存,如果此時內存不足導致new char拋出異常,m_pData將是一個空指針,這樣非常容易導致程序崩潰。也就是說一旦在賦值運算符內部拋出一個異常,CMyString的實例將會不再保持有效的狀態,這就違背了異常安全性的原則。

    要想在賦值運算符函數中實現異常安全性,我們有兩種方法:一個簡單的方法就是我們先用new分配新內容再用delete釋放已有的內存,也就是只在分配內容成功后再釋放原來的內容,也就是當分配內存失敗時我們能夠確保CMyString的實例不會被修改,我們還有一個方法就是先創建一個臨時實例,再交換臨時實例和原來的實例。

CMyString& CMyString::operator=(const CMyString& str)
{
	if(this != &str)
	{
		CMyString strTemp(str);

		char* pTemp = strTemp.m_pData;
		strTemp.m_pData = m_pData;
		m_pData = pTemp;
	}

	return *this;
}
在這個函數中,我們先創建一個臨時實例strTemp,接着把strTemp.m_pData和實例自身的m_pData做交換。由於strTemp是一個局部變量,但程序運行到if的外面就會除了該變量的作用域,就會自動調用strTemp的西溝函數,把strTemp.m_pData所指向的內存釋放掉。由於strTemp.m_pData指向的內存就是實例之前m_pData的內存,這就相當於自動調用析構函數釋放實例的內存.


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com