題目:如下位類型CMyString的聲明,請為該類型添加賦值運算函數。
class CMyString{
public:
CMyString(char *pData = NULL);
CMyString(const CMyString& str); //拷貝構造函數
~CMyString();
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;
}
在前面的函數中,我們在分配內存之前先用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所指向的之前的m_pData的內存,這就相當於自動調用析構函數釋放實例的內存。
在新的代碼中,我們在CMyString的構造函數里用new分配內存。如果由於內存不足拋出諸如bad_alloc等異常,我們還沒有修改原來實例的狀態,因此實例的狀態還是有效的,這也就保證了異常安全性。
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。