關於C 的右值引用的一些看法

2022-01-09 22:36:08 字數 2537 閱讀 1379

關於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_ptrshared_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操作就懵逼了,一直想探個究竟,但是右值以及右值引用思考了好長時間,就是不得要領,今天終於有所收穫,寫下第一篇部落格,一方面為了幫助一些剛入門的朋友,另一方面也是幫助自己今後複習。左值是乙個持久的量,右值是乙個短暫的量。那怎麼算持久怎麼算短暫呢?取決於我的 裡有沒有乙個變數來儲存...