賦值運算子函式作為類的乙個成員函式,主要用於物件之間的賦值。類一般都有預設的賦值運算子函式,然而預設賦值運算子函式只會淺拷貝,無法滿足需求,有時還會產生致命錯誤。
如下:
class
cstring
cstring
(const cstring& str)
:_buf
(nullptr
)cstring
(const
char
* str)
:_buf
(nullptr)~
cstring()
}private
:char
* _buf;};
intmain()
}
如上**所示,如果使用預設賦值運算子函式,str2 = str1;
str2和str1將會指向同一塊記憶體位址,當離開**塊作用域之後,str1和str2都將析構,這裡將產生double free 記憶體錯誤。
對於這種需要深拷貝的賦值運算子函式需要自己定義。
下面是針對cstring類的幾種賦值運算子函式的實現:
cstring& cstring::
operator=(
const cstring& str)
delete
_buf;
_buf =
nullptr
;const
int size =
strlen
(str._buf)+1
; _buf =
newchar
[strlen
(str._buf)+1
];memset
(_buf,
0, size)
;strcpy
(_buf, str._buf)
;return
*this
;}
如上賦值運算子返回值定義成引用型別,方便連續賦值,如以上實現就是乙個深拷貝。但是嚴格來講也是存在問題的,當new char 丟擲異常時,由於在這之前已經str1 = str2 = str3;
賦值運算子引數定義成物件的常量引用,主要保證不會修改被賦值的物件;
實現中,先判斷是否是物件自己,如果是則返回自己,
接著釋放_buf記憶體,並置空
最後申請新的記憶體,將引數str中_buf資料拷貝到當前物件的buf中。
delete _buf
,則當前物件就不能在保持有效狀態,這就違背了異常安全性原則。好的做法應該是先申請記憶體,再釋放記憶體,如下:
cstring& cstring::
operator=(
const cstring& str)
const
int size =
strlen
(str._buf)+1
;char
* buf =
newchar
[strlen
(str._buf)+1
];memset
(_buf,
0, size)
;delete
_buf;
_buf = buf;
strcpy
(_buf, str._buf)
;return
*this
;}
還有另一種更優雅的實現:
cstring& cstring::
operator=(
const cstring& str)
cstring strtemp
(str)
;char
* buf = strtemp._buf;
strtemp._buf = _buf;
_buf = buf;
return
*this
;}
這種實現將new出現異常的情況轉移到拷貝建構函式中,即便出現異常也不會影響當前物件的狀態。一般我們自己定義的類都需要實現賦值運算子函式,特別是含有動態記憶體的物件。賦值運算子函式要保證物件的賦值是深拷貝,而且在實現的過程中也要注意異常安全性,這樣才能能寫出健壯而優雅的**。
賦值運算子函式
賦值運算子函式的 需要關注幾點 1 是否把返回值的型別宣告為該型別的引用,並在函式結束前返回例項自身的引用 即 this 只有返回乙個引用,才可以允許連續賦值。否則如果函式的返回值void,該賦值運算子將不能做連續賦值。2 是否把傳入的引數的型別宣告為常量引用。引數宣告為引用可以避免無謂的消耗,提高...
賦值運算子函式
題目 如下為型別cmystring的宣告,請為該型別新增賦值運算子函式。class cmystring 1 經典解法,初級程式設計師 cmystring cmystring operator const cmystring str 2 考慮異常安全的解法,高階程式設計師 cmystring cmys...
賦值運算子函式
型別宣告如下 class cmystring 請為上型別新增賦值運算子函式.經典解法 cmystring cmystring operator const cmystring str 考慮異常安全性解法 cmystring cmystring operator const cmystring str...