本節書摘來自異步社群出版社《21天學通c++(第7版)》一書中的第12章,第12.4節,作者: 【美】siddhartha rao, 【德】nicolai m. josuttis,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。
21天學通c++(第7版)
operator()讓對象像函數,被稱為函數運算符。函數運算符用于标準模闆庫(stl)中,通常是stl算法中。其用途包括決策。根據使用的操作數數量,這樣的函數對象通常稱為單目謂詞或雙目謂詞。下面分析一個非簡單的函數對象,如程式清單12.11所示,以便了解使用如此有意思的名稱的原因!
程式清單12.11 一個使用operator()實作的函數對象

輸出:
分析:
第8~11行實作了operator(),然後在main()函數的第18行使用了它。注意,之是以能夠在第18行将對象mdisplayfuncobject用作函數,是因為編譯器隐式地将它轉換為對函數operator()的調用。
是以,這個運算符也稱為operator()函數,對象cdisplay也稱為函數對象或functor。第21章将詳盡地讨論這個主題。
c++11
用于高性能程式設計的移動構造函數和移動指派運算符
移動構造函數和移動指派運算符乃性能優化功能,屬于c++11标準的一部分,旨在避免複制不必要的臨時值(目前語句執行完畢後就不再存在的右值)。對于那些管理動态配置設定資源的類,如動态數組類或字元串類,這很有用。
1.不必要的複制帶來的問題
請看程式清單12.5實作的加法運算符,注意到它建立并傳回一個拷貝;減法運算符亦如此。使用下面的文法建立新的mystring執行個體時,情況将如何呢?
這種方式非常直覺,它使用雙目加法運算符(+)将三個字元串拼接起來。該運算符的實作類似于下面這樣:
這個加法運算符(+)讓您能夠使用直覺的表達式輕松地拼接字元串,但也可能導緻性能問題。建立sayhello時,需要執行加法運算符兩次,而每次都将建立一個按值傳回的臨時拷貝,導緻執行複制構造函數。複制構造函數執行深複制,而生成的臨時拷貝在該表達式執行完畢後就不再存在。總之,該表達式導緻生成一些臨時拷貝(準确地說是右值),而它們在目前語句執行完畢後就不再需要。這一直是c++帶來的性能瓶頸,直到最近才得以解決。
c++11解決了這個問題:編譯器意識到需要建立臨時拷貝時,将轉而使用移動構造函數和移動指派運算符——如果您提供了它們。
2.聲明移動構造函數和移動指派運算符
移動構造函數的聲明文法如下:
從上述代碼可知,相比于正常指派構造函數和複制指派運算符的聲明,移動構造函數和移動指派運算符的不同之處在于,輸入參數的類型為myclass&&。另外,由于輸入參數是要移動的源對象,是以不能使用const進行限定,因為它将被修改。傳回類型沒有變,因為它們分别是構造函數和指派運算符的重載版本。
在需要建立臨時右值時,遵循c++的編譯器将使用移動構造函數(而不是複制構造函數)和移動指派運算符(而不是複制指派運算符)。移動構造函數和移動指派運算符的實作中,隻是将資源從源移到目的地,而沒有進行複制。程式清單12.12示範了如何使用這兩項c++11新增功能對mystring類進行優化。
程式清單12.12 除複制構造函數和複制指派運算符外,還包含移動構造函數和移動指派運算符的mystring類
沒有移動構造函數和移動指派構造函數(将第95~119行注釋掉)時的輸出:
添加移動構造函數和移動指派構造函數後的輸出:
這個代碼示例很長,但大部分都在本書前面介紹過。在該程式清單中,最重要的部分是第95~119行,其中實作了移動構造函數和移動指派運算符。這些c++11新增功能生成的輸出使用粗體表示。注意到相比于沒有這兩個實體時,輸出變化很大。如果您檢視移動構造函數和移動指派運算符的實作,将發現移動語義基本上是通過接管移動源中資源的所有權實作的,如移動構造函數的第101行和移動指派運算符的第114行所示。接下來,将移動源指針設定為null,如第102和115行所示。這樣,移動源被銷毀時,通過析構函數(第16~20行)調用的delete什麼也不會做,因為所有權已轉交給目标對象。注意到在沒有移動構造函數時,将調用複制構造函數,它對指向的字元串進行深複制。總之,移動構造函數避免了不必要的記憶體配置設定和複制步驟,進而節省了大量的處理時間。
移動構造函數和移動指派運算符是可選的。不同于複制構造函數和複制指派運算符,如果您沒有提供移動構造函數和移動指派運算符,編譯器并不會添加預設實作。
對于管理動态配置設定資源的類,可使用c++11新增的這項功能對其進行優化,避免在隻需臨時拷貝的情況下進行深複制。
本文僅用于學習和交流目的,不代表異步社群觀點。非商業轉載請注明作譯者、出處,并保留本文的原始連結。