赋值运算符函数严谨性的几点思考
生活随笔
收集整理的這篇文章主要介紹了
赋值运算符函数严谨性的几点思考
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1. 需求
class CMyString { public:CMyString(char* pData = NULL);CMyString(const CMyString& str);~CMyString(void); private:char* m_pData; };2.定義賦值運算符函數需要考慮的四個準則
- 是否把返回值的類型聲明為該類型的引用,并在函數結束前返回實例自身的引用(即*this)。只有返回一個引用,才可以允許連續的賦值。否則如果該函數的返回值是void,應用該賦值運算符不能做連續的賦值。假設有3個連續的CMyString對象:str1=str2=str3,將不能編譯通過。
- 是否把傳入的參數類型生命為常量引用。如果傳入的參數不是引用而是實例,那么從形參到實參會調用一次復制構造函數。辦參數聲明為引用可以避免這樣的無謂的消耗,從而提高代碼的效率。同時,我們在賦值運算符函數內不會改變差UN入的實例的狀態,因此應該為傳入的引用參數加上const關鍵字。
- 是否釋放實例自身已有的內存。如果我們在分配新內存之前,忘記了釋放自身已有的空間,程序將會發生內存泄漏。
- 是否判斷傳入的參數與當前的實例(*this)是不是同一個實例。如果是同一個,則沒有必要進行復制操作,直接返回當前實例的指針。如果事前不判斷就進行賦值,那么在釋放實例自身的內存的時候就會導致嚴重的錯誤:當*this和傳入的參數是同一個實例時,一旦釋放了自身的內存,傳入的參數的內存也被同時釋放,因此再也找不到需要復制的內容了。
3.初級程序員的解法
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; // 函數結束前返回自身的引用 }4.高級程序員的解法_異常安全性原則
在3中,我們在分配內存之前先用delete釋放了實例m_pData的內存。如果私事內存不足導致new char拋出異常,m_pData將是一個空指針,這樣非常容易導致程序崩潰。也就是說,一旦在賦值運算符函數內部剖出一個異常,CMyString的實例不在保持有效的狀態,這就違背了一場安全性(Exception Safety)原則。
要想在賦值運算符函數中實現異常安全性,有兩種方法。一個簡單的方法是我們先用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的內存,相當于自動調用析構函數釋放實例的內存。 與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的赋值运算符函数严谨性的几点思考的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 体验微软反间谍软件及恶意软件清除工具
- 下一篇: BCB窗体移动