這是一道c++的面試題,下面在這篇部落格中分析一下這個問題。先上題目:
//題目:如下為型別cmystring的宣告,請為該型別新增賦值運算子函式。class cmystring
;
拿到這個題目,如果你看過effective c++這本書,**應該很容易就能夠完成,在寫的時候要注意下面的乙個要點:
1>賦值運算子要返回該例項自身的引用(*this),因為只有返回乙個引用才可以允許連續賦值操作。
2>把傳入的引數的型別宣告為常量引用,這樣能夠避免傳入例項時的值拷貝,避免複製建構函式的呼叫。同時賦值運算子不會改變傳入的例項的狀態,因此要在傳入的引數前加上const關鍵字。
3>要在分配新的記憶體之前釋放自身已有的空間,否則程式會出現記憶體洩露。賦值運算子執行的是賦值操作,在賦值運算子之前肯定呼叫過物件的建構函式或者拷貝建構函式,因為乙個物件在例項化的時候肯定會有乙個初始化的過程。這裡必須釋放原來的堆記憶體空間,因為m_pdata可能變得更長了,原來的空間可能已經不夠用了。
4>判斷傳入的引數和當前的例項(*this)是不是同乙個例項,如果是同乙個例項的話就直接返回,防止str1=str1這樣的沒有意義的操作。如果不判斷這個 ,結果很嚴重,如果釋放了例項的堆記憶體空間,也就等於釋放了引數的堆空間(雖然引數是const的,但是這次的釋放是通過this物件釋放的,不是通過引數物件釋放的),就沒有了這個物件的完整備份,那麼這個物件就永遠的從這個世界上消失了。
cmystring& cmystring::operator=(const cmystring& str)delete m_pdata;
m_pdata = null;
m_pdata = (char*)malloc(strlen(str.m_pdata) + 1);
strcpy(m_pdata, str.m_pdata);
return *this;
}
上面的**雖然能夠解決問題,但是存在安全隱患,在分配記憶體之前先用delete釋放了例項m_pdata的記憶體,如果此時記憶體不足,導致new char申請記憶體失敗,m_pdata將是乙個空指標,這很容易發生異常,因為我們認為它不是乙個空指標。
這裡要處理的是防止new堆記憶體的時候,由於記憶體不足等原因導致異常,而是當前物件的完整性遭到破壞。也就是說你要異常要在操作當前物件之前,不能在操作當前物件的過程中異常,使得這個當前物件不完整。
解決的辦法有兩種:
1>先用new分配新內容,然後再用delete釋放已有內容,也就是分配成功之後再分配新的內容,這樣就能保證在分配失敗之後,原來的cmystring的例項不會被修改。
2>先在棧中建立乙個臨時例項,然後在交換臨時例項和原有例項
下面給出2>的**實現:
cmystring& cmystring::operator=(const cmystring& str)cmystring tempstr(str);
//交換臨時例項和原有例項的指標指向
char *pdata = tempstr.m_pdata;
tempstr.m_pdata = m_pdata;
m_pdata = pdata;
return *this;
}
注意**的技巧的地方在於,這個tempstr是在棧中開闢的臨時的例項,在這個函式執行結束以後,這個函式棧要銷毀,所以tempstr的析構函式會自動的呼叫,當析構函式呼叫的時候肯定會自動的釋放原來的那塊堆記憶體的。
在新的**中,在cmystring的建構函式裡用new分配記憶體。如果由於記憶體不足丟擲如bad_alloc等異常,我們還沒有修改原來的例項的狀態,因此例項的狀態還是有效的。
其實上面的**應該有try-catch模組,這樣就能處理異常,同時不會是程式終止。改進的實現的唯一目的就是為了保證在丟擲異常(可能因為記憶體不足)時,原來的例項沒有被修改過。也就是說,要拋異常你就早點拋,在我修改原來例項之前就拋,要麼你就不要拋。
C 運算子過載賦值運算子
自定義類的賦值運算子過載函式的作用與內建賦值運算子的作用類似,但是要要注意的是,它與拷貝建構函式與析構函式一樣,要注意深拷貝淺拷貝的問題,在沒有深拷貝淺拷貝的情況下,如果沒有指定預設的賦值運算子過載函式,那麼系統將會自動提供乙個賦值運算子過載函式。賦值運算子過載函式的定義與其它運算子過載函式的定義是...
C 賦值運算子過載
c 賦值運算子過載,為什麼要返回引用?查了許多資料,基本有兩種說法 一 c c 賦值運算子的本意為 返回左值的引用 左值 賦值號左面的變數而非其值 可用以下程式段測試 int a,b 3,c 2 a b c cout 對於x y x,y均為物件時 若不返回左值的引用,將會生成臨時物件。如果不處理x ...
C 過載賦值運算子
c 類建立時,會產生乙個預設的賦值運算子函式 a operator const a 普通類例項之間賦值可能沒問題,但當類成員變數中有指標引用的動態記憶體時,複製後只是簡單地將指標值複製,而沒有將其指向的動態記憶體也拷貝乙份,這樣即多個類例項內的指標指向同一動態記憶體,當類例項析構時,會導致這塊動態記...