STL swap潛在的危險

2021-09-08 23:09:13 字數 2722 閱讀 8320

在學習c++程式設計的時候,都使用過標準庫(stl)當中的swap,但更多的是swap(int,int)或 者等等一些基本的型別,發散一下是否也可以用來置換自定義的乙個型別,比如說某一class(定義乙個class相當於定義乙個type了),先不從效率上來考慮,看看可行性如何。ps:歡迎討論。

在stl中的swap大概是這樣的實現:

templatevoid swap(t& a,t& b)

在裡面很清楚先先呼叫t型別的拷貝建構函式構造乙個臨時變數temp,然後利用這個中間變數將a和b進行調換。其中的「=」很陰人。

編譯器在編譯乙個空類的時候自動會生成四個預設的函式,分別是預設建構函式,析構函式,拷貝建構函式,賦值運算子(operator=),取址運算子(operator&)(一對,乙個非const的,乙個const的)

在csdn裡面找了個帖子,裡面有討論。有個疑問:都有了賦值運算子函式了,是不是就不需要再過載它了

在都是預設的情況下,拷貝建構函式和賦值運算子的功能是一樣的,也就是說它們都是淺拷貝,當然當淺拷貝能夠滿足我們的需求的時候,就沒有必要去過載它們了。就比如:

class myclass

};

裡面的成員變數都是基本的型別,而沒有涉及到指標,這個時候無論是拷貝建構函式和賦值運算子都能夠滿足我們的要求。但是:

class myclass

~myclass()

}};

這個時候淺拷貝(這裡所謂的淺拷貝包括了拷貝建構函式和運算子過載)顯然就不能滿足我們的要求,只要有乙個物件中途被銷毀,另乙個就要遭殃了(下圖很明確的說明了)。

預設的賦值運算子過載不能夠滿足我們的要求,因此我們要重寫。還記得上面提過的swap在stl內的實現嗎,對,裡面就用到了運算子過載,當呼叫stl swap來置換兩個物件的時候,很有必要根據實際情況對swap做出必要的防範,用心設計好運算子過載。下面的討論都是基於呼叫stl swap來置換兩個物件且類裡面定義了指標變數,就比如上面的第三段**;至於不含有指標變數的很明顯,預設的預設的運算子過載能夠滿足我們的要求。

試著寫這樣乙個運算子過載:

myclass& operator=(const myclass& mc)

一眼看上去是對的,上面的**缺少安全的檢測,因此有缺陷:運算子左值即mc的成員變數letter指標不一定是有效的,即可能它是乙個空指標,總不能給他強加個程式崩潰後的罪名,執行起來會有錯誤。

改進後:

myclass& operator=(const myclass& mc)

return *this;

}

假設有主程式:

int main()

當運算子左值的變數letter指標和右值變數letter指標都不為空**,過程很順利(下圖)

但是左值變數letter指標為空的情況下,結果很意外(下圖)

右值變數letter指標為空的情況也一樣,很意外(下圖)

上面的情況都忽略了對左值變數letter指標為空情況的處理,進一步改進**:

myclass& operator=(const myclass& mc)

else

letter = null;//如果左值letter為空指標,也讓右值letter指標為空

return *this;

}

於是對於運算子左右值其中之一為空的情況有了新的結果(下圖),swap成功了

無論是哪種情況,這種**都不會有失誤的時候,甚至當左右值letter都為null的時候都不會有錯。細心的你一定會有鬼點子(好點子)來鄙視上面那種做法的繁瑣(確實夠繁瑣)。考慮到

int main()

這段程式給我很大的啟發,確實,它不用再去分配什麼空間之類的東西,同時也不用strcpy,畢竟如果資料量較大的話,這些操作花費的時間是不可忽略的。但是「下面的討論都是基於呼叫stl swap來置換兩個物件且類裡面定義了指標變數」,

所以這種思路暫時還不能用在這裡。

《effective c++》裡面有種做法,就是設定乙個swap成員函式,在裡面再呼叫stl裡面的swap來交換letter指標(更聰明,也容易理解,**了)和其他的資料。所以標準庫(stl)中的swap無疑是可以用來置換兩個自定義型別的(比如說class),但是從上面囉嗦那麼多就知道需要注意的地方太多了,而且效率也不高,因此雖然標準庫(stl)強大,我們應該有選擇的利用。

搗亂小子 2011-12-18

ps:歡迎討論:)

整型表示式比較的潛在危險

在程式裡頭經常會用到整數之間的大小比較,但是其中潛在的危險卻往往被忽略了。例如乙個記憶體拷貝函式 void memcpy void pto,void pfrom,size t size 這個函式正確嗎?如果你認為它永遠都不可能跳出那個該死的迴圈就對了。size t是乙個無符號整數型別 vc6.0 t...

redis潛在的瓶頸

redis單執行緒處理io請求效能瓶頸 1 任意乙個請求在server中一旦發生耗時,都會影響整個server的效能,也就是說後面的請求都要等前面這個耗時請求處理完成,自己才能被處理到。耗時的操作包括以下幾種 a 操作bigkey 寫入乙個bigkey在分配記憶體時需要消耗更多的時間,同樣,刪除bi...

指標的危險

指標的危險 下面的 有沒有問題?如果有的話,問題在 intarray array size int pi for pi array 0 pi array array size 有兩個錯誤。對增值後的指標進行解引用時,陣列的第乙個元素並沒有被清零。另外,指標在越過陣列的右邊界以後仍然進行解引用,它將把...