[英]Operator overloading with memory allocation?
下面的句子來自Bruce Eckel 的C ++和Java的正面遺產 ,關於C ++中的運算符重載:
C ++具有堆棧分配和堆分配,您必須重載操作符以處理所有情況並且不會導致內存泄漏。 確實很困難。
我不明白運算符重載與內存分配有什么關系。 任何人都可以解釋它們是如何相關的嗎?
我可以想象幾種可能的解釋:
首先,在C ++中, new
和delete
都是運算符; 如果您選擇通過重載這些運算符來為對象提供自定義分配行為,則必須非常小心這樣做以確保不會引入泄漏。
其次,某些類型的對象需要重載operator=
以避免內存管理錯誤。 例如,如果您有一個引用計數智能指針對象(如Boost shared_ptr),則必須實現operator=
,並且必須確保正確執行。 考慮這個破碎的例子:
template <class T>
class RefCountedPtr {
public:
RefCountedPtr(T *data) : mData(data) { mData->incrRefCount(); }
~RefCountedPtr() { mData->decrRefCount(); }
RefCountedPtr<T>& operator=(const RefCountedPtr<T>& other) {
mData = other.mData;
return *this;
}
...
protected:
T *mData;
};
這里的operator=
implementation被破壞了,因為它不管理mData
和other.mData
上的引用計數:它不會減少mData
上的引用計數,導致泄漏; 並且它不會增加other.mData
上的引用計數,從而導致可能的內存故障,因為在所有實際引用消失之前,可以刪除指向的對象。
請注意,如果沒有為類顯式聲明自己的operator=
,編譯器將提供一個默認實現,其行為與此處顯示的實現相同 - 即,對於此特定情況完全中斷。
正如文章所說 - 在某些情況下,您必須重載操作符,並且必須小心正確處理所有情況。
編輯 :對不起,我沒有意識到該引用是一篇在線文章,而不是一本書。 即使閱讀了完整的文章后,目前還不清楚是什么意思,但我認為Eckel可能指的是像我上面描述的第二個那樣的情況。
new和delete實際上是C ++中的運算符,您可以覆蓋它們以提供自己的自定義內存管理。 看看這里的例子 。
運營商是職能。 僅僅因為他們添加語法糖並不意味着你不必小心記憶。 您必須像管理任何其他成員/全局/朋友功能一樣管理內存。
當您實現包裝器指針類時重載它時,這一點尤為重要。
然后通過重載operator+
或operator+=
來進行字符串連接。 有關更多信息,請查看basic_string
模板。
如果您要比較Java和C ++之間的運算符重載,那么您就不會討論new
和delete
- Java沒有為new提供足夠的內存管理細節,也不需要刪除。
您不能為指針類型重載其他運算符 - 至少一個參數必須是類或枚舉類型,因此他不能討論為指針提供不同的運算符。
因此,C ++中的運算符對值或const引用值進行操作。
操作符對值或const引用值的運算符返回除值之外的任何內容都是非常不尋常的。
除了所有C ++函數常見的明顯錯誤之外 - 返回對堆棧分配對象的引用(與內存泄漏相反),或者返回對使用new
而不是值創建的對象的引用(通常不再執行此操作)在學習之前的職業生涯中,曾經很難找到一個常見的操作員有記憶問題的場景。
因此,根據正常使用模式,操作數是堆棧還是堆分配,不需要創建多個版本。
運算符的參數是作為值或引用傳遞的對象。 C ++中沒有可移植的機制來測試對象是分配堆還是堆棧。 如果對象是按值傳遞的,它將始終在堆棧上。 因此,如果需要在兩種情況下更改運算符的行為,則無法在C ++中進行移植。 (在許多操作系統上,您可以測試指向對象的指針是否位於通常用於堆棧的空間或通常用於堆的空間中,但這既不便攜也不完全可靠。)(即使您可以擁有運算符)以兩個指針作為參數,沒有理由相信對象是堆分配只是因為它們是指針。這些信息在C ++中根本就不存在)
您獲得的唯一重復是諸如operator []之類的情況,其中相同的運算符用作存取器和增變器。 那么有一個const和一個非const版本是正常的,所以你可以設置接收器不是const的值。 這是一件好事 - 無法改變(可公開訪問的狀態)已標記為常量的對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.