陷阱重重的C++賦值重載函數operator=

曾經有C++高手說過:看一個C++程序員功底是否夠硬,讓他寫個賦值重載函數就能看出來了!在我看來,這種說法並不誇張。因爲能將operator=函數寫好確實需要紮實的基礎,其中的陷阱真不少。

  • 陷阱一:不懂規避自我拷貝

先看代碼

string& string::operator=(const string& rhs)
{
    if (m_pStr != NULL)
        delete [] m_pStr;
    m_pStr = new char[....];
    strcpy(....);

    return *this;
}

此代碼就是沒有規避自我賦值,那麼如果進行以下的調用,那麼後果很嚴重。

string myStr("abc");
myStr = myStr;

賦值操作中,會先把自己的數據delete掉,然後再strcpy一個空值,程序立馬掛了。

所以,在賦值函數開始的時候,需要防止自我複製。寫法如下:

string& string::operator=(const string& rhs)
{
    // 防止自我賦值
    if (this == &rhs)
        return * this;

    ...
}
但有些書籍上面使用以下寫法,不敢苟同。

string& string::operator=(const string& rhs)
{
    // 防止自我賦值
    if (*this == rhs) // 這只是判斷內容是否相同,並不能判定是自我賦值!!!
        return * this;

    ...
}
  • 陷阱二:返回值的類型用啥

在初學者的羣體當中,有出現諸如以下幾種返回值版本:

// 版本一
string string::operator=(const string& rhs)
{
    ...
    return * this;
}

// 版本二
const string& string::operator=(const string& rhs)
{
    ...
    return * this;
}

// 版本三
string* string::operator=(const string& rhs)
{
    ...
    return this;
}

版本一的缺陷:多了一個臨時對象的生成和拷貝,影響程序效率。

版本二的缺陷:非const類型的變量想得到它的連續賦值變得不可能,而且編譯器也會報錯。

版本三的缺陷:不能保持連續賦值時類型的統一性,違反了編程的慣例。如

// 版本三的缺陷
string a, b, c;
*a = b = c; // 必須這樣賦值給a,類型不統一!! 
  • 陷阱三:未做深拷貝

任何未做深拷貝的版本都退化爲默認版本。

string& string::operator=(const string& rhs)
{
    if (this == &rhs) return *this;

    if (m_pStr != NULL)
        delete [] m_pStr;
    m_pStr = rhs.m_pStr; // 淺拷貝

    return *this;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章