關於c++中的右值引用的詳細可以看這一批博文《從4行**看右值引用》。那一篇博文詳細結合四行簡單的**詳細介紹了右值引用的使用方法和一些場景,非常實用。
而本篇博文主要介紹一下我在學習右值引用的一些心得。因為在學習右值引用的時候,有一些地方非常難理解。所以寫下這一篇博文,防止遺忘,由於對於c++涉獵不多,所以有一些不正確的地方,歡迎斧正。
對於普通開發者來說,右值引用的好處在於可以將保證在取用函式返回值的時候,減少一次複製的機會。如:
#include using namespace std;
class test
int a = 0;
~test()
test(const test &a)
};test gettest()
int main()
使用編譯選項-fno-elide-constructors,可以得到結果
構造
複製析構
複製析構
析構
可以發現,為了保證正常執行和堆疊正常,程式對test物件經過了一次構造和兩次複製。分別是
gettest()
函式中test af
的構造,由於af是gettest()
的臨時變數,因此此時使用的記憶體空間是gettest()
裡面的棧1。
為了把af從gettest()
的棧中取出來,於是將把af指向的test物件複製到了main()
的棧,由於程式「並不知道」接下來的操作,所以此時物件的存在就是乙個臨時的。語句執行完,它就析構了。
為了儲存這乙個物件,我們使用了a,而為了將上一步得到的值複製到a,程式又進行了一次複製。
以上便是程式的全過程。而可以很清楚的發現,第2次複製得到的值和第3次複製得到的值,它們都位於main()
的堆疊空間內的,他們的生命週期都是一樣的,和main()
一樣長。那麼我們有沒有辦法可以減少第3次的複製呢?
在沒有右值引用的時候有兩種方法。
靠編譯器優化2。
使用const test&
,常量引用。
第一種方法不表,以目前的編譯器優化,的確可以獲得非常多的優惠,但是這些編譯器提供的,並不是語法提供的,不同的編譯器可能存在不一樣的表現。第二種在需要改變返回值的時候非常麻煩。
而右值引用可以解決這一問題。我們將main()
函式的**改為
int main()
編譯執行後得到額結果為
構造
複製析構
析構
可以看到,程式減少了一次複製。這一次的減少就是上述的第3次的複製。而且此時的變數a可以隨意的更改。
那我們可以把第二次的複製也去掉嗎?當然可以,比如把gettest()
的返回值改為test&&
,然後給af加上std::move
強制轉換成右值。但是,這樣的操作破壞了程式的堆疊,會出現很大的問題。
unique_ptr
是c++中智慧型指標的一部分,另外還有auto_ptr
和shared_ptr
。但是剛剛使用c++不久,所以只對shared_ptr
有一定的了解,而auto_ptr
由於一些原因已經被棄用了。unique_ptr
只允許乙個智慧型指標物件擁有指標。而shared_ptr
則允許多個,其內部有乙個引用計數器,當引用為0時便釋放空間,因此相對於unique_ptr
,其所佔的記憶體空間較大,使用的時候,效率也相對較低。
unique_ptr
的實現必須保證不共享其指標,不複製到其他的unique_ptr
,也不能使用值傳遞到函式裡面。要將其所有權交給其他變數,只能通過「移動」的操作。
為了保證移動的語義上的正確性,被移動的unique_ptr
必須為右值。因為右值是被認為是即將消亡的值(將亡值),所以移動操作可以把被移動的unique_ptr
的引用值為nullptr。
std::move
是將乙個左值轉換為右值,在內部實現直接使用了強制轉換static_cast()
。它一般用於將左值轉換為右值,在unique_ptr
轉移的時候需要使用。一般來說,使用了move後,該物件就不應該繼續使用了。
std::forward
即完美**,保證引數在傳遞過程中屬性不變,右值還是右值,左值還是左值。
此處表達可能有一些不正確,因為所有的函式呼叫及其區域性變數應該都是在乙個棧上。但是在函式結束的時候,必須要恢復棧的指標。這一步便需要把其區域性變數全部刪除,因此可以認為其區域性變數是位於函式的棧中。
去掉編譯選項-fno-elide-constructors
------------恢復內容結束------------
關於右值引用的一些理解
右值引用之前看過不少次了,但過一段時間就忘了,這裡簡單整理一下我的理解 右值引用主要用來實現 移動語義 和 完美 1.移動語義 使用上可以用std move 把引數強制轉換成右值 我理解就是和淺拷貝很像,不過淺拷貝是多個指標指向堆上的空間,可能會重複釋放從而出錯,而移動語義是只有乙個指標占有堆上的空...
右值引用的一些測試
編譯 g std c 11 g fno elide constructors o0 test.cc o test fno elide constructors 用來關閉編譯器優化 include class a a 拷貝建構函式 a const a a value a.value 移動建構函式 a ...
關於c 的 右值 右值引用 move
第一次接觸c move操作就懵逼了,一直想探個究竟,但是右值以及右值引用思考了好長時間,就是不得要領,今天終於有所收穫,寫下第一篇部落格,一方面為了幫助一些剛入門的朋友,另一方面也是幫助自己今後複習。左值是乙個持久的量,右值是乙個短暫的量。那怎麼算持久怎麼算短暫呢?取決於我的 裡有沒有乙個變數來儲存...