String類賦值運算符函數

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

class CMyString
{
public:
    CMyString(char* pdata = NULL);
    CMyString(const CMyString& str);
    //賦值函數
    CMyString& operator=(const CMyString& str); 

    ~CMyString(); 

private:
    char* m_data;
};

面試官考察的點:
1、 是否把返回值的類型聲明爲該類型的引用,並在函數返回前,返回自身的引用(*this)。只有返回一個引用,纔可以允許連續賦值。如果函數的返回值爲void,則像str1=str2=str3這樣的連續賦值將不會被通過
2、 是否把傳入的參數類型聲明爲常引用。如果傳入的參數不是引用而是實=實例的話,那麼從形參到實參要進行一次拷貝構造函數的調用,把參數聲明爲引用,可以避免無謂的消耗,提高效率。同時,在賦值的時候,不應該改變傳入參數的狀態,所以,應該聲明爲常引用,加上const關鍵字
3、 是否釋放自身的空間,否則程序將出現內存泄漏
4、 避免自賦值。判斷傳入的參數是否和當前的實例*this是一個實例,如果是同一個實例,則不進行賦值操作,直接返回。如果事先不進行判斷,在釋放自身實例的內存的時候就會出現問題,一旦釋放了自身的內存,傳入的參數的內存也同時釋放了,因此再也找不到需要賦值的內容了

//初級程序員解法:

CMyString& CMyString::operator=(const CMyString& str)
{
    //防止自賦值
    if (&str == this)
        return *this;
    //釋放自身空間
    delete[] m_data;
    m_data = NULL; 
    //分配空間,賦值
    m_data = new char[strlen(str.m_data)+1]; 
    strcpy(m_data, str.m_data); 

    //返回自身引用
    return *this; 
}

//考慮異常安全的解法,高級程序員必備
在前面的函數中,我們在分配內存之前先delete釋放了自身的內存。但是如果此時內存不足,分配內存的時候拋出異常,那麼m_data將是一個空指針,很容易導致程序崩潰,違背了異常安全原則
要想在賦值函數中實現異常安全性。有兩種方法:1、一個簡單的方法是先用new分配新內容,再delete釋放已有的內容,這樣在分配成功之後再釋放原來的內容,也就是當分配失敗時可以保證CMyString的實例不會被修改。2、還有一個更好的方法就是創建一個臨時對象,再交換臨時對象和原來對象

CMyString& CMyString::operator=(const CMyString& str)
{
    if (&str != this)
    {
        //先通過拷貝構造函數創建一個臨時對象 
        CMyString strtmp(str);
        //交換臨時對象和自身的m_data
        char* pTmp = m_data;
        m_data = strtmp.m_data;
        strtmp.m_data = pTmp; 

    }
    return *this;
}

這個函數中,先創建一個臨時對象,然後交換臨時對象和實例自身的m_data,由於臨時對象是一個局部對象,出了if語句就會自動調用臨時對象的析構函數,就會把臨時對象所指的那塊內存釋放掉。
在這個新的代碼中,我們在CMyString的構造函數裏用new分配內存,如果內存不足拋出異常,這時,我們還沒有修改原來實例的狀態。就保證了異常安全性

發佈了73 篇原創文章 · 獲贊 107 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章