標籤:

C++有右值引用以後是否可以直接return 字元串、結構體而無需考慮大量數據複製的性能問題了?

如果返回的字元串非常大有關係嗎(我知道大字元串會在堆中分配,但不知道棧中要佔多少內存,以及處理要多久)?

如果是一個比較大的結構體有關係嗎?

感覺這種直接return的寫法好爽(尤其是處理字元串的時候),就是怕性能問題。

java,c#等其他語言對象都是個指針,不存在這個問題。


返回臨時對象、或者返回std::move(已經不會被繼續使用的左值引用)是沒有問題的。

P.S.

必須指出,其他答案說的RVO跟這個東西的情況不是太一樣,因為那些東西只能處理返回臨時對象的那前面的一半,後面的一半沒有std::move還是對付不了。


std::mt19937,整個C++標準庫里最大的類,4004位元組,想想也不能直接返回。

其他的差不多都行,心虛的話跑個benchmark,別腦補性能瓶頸


首先RVO是有條件的。

X a(1), b(2);

if(blabalbal){

return a;

}

if(balbbbb){

return b;

}

return a;

這種有多路返回分支,並且返回的不是右值,而且blabla裡面可能對a,b的內容有改變,是不能做RVO的,你沒法保證有一天你的代碼不會被改成這個樣子。

其次,右值拷貝依然是拷貝,只是相對來說拷貝的可能會輕鬆一點,可以利用pimpl+交換之類的方法快速掏空右值。但是對對象結構是要求的,不是每個類都可以實現右值拷貝比左值快的。


void WriteString(string result)

void WriteBigStruct(BigStruct result)


一直就有RVO和NRVO,17之後Copy elision變成強制,17之前像話的編譯器也都會做。只要函數里用對了就行(比如說,不要在函數的不同路徑里返回不同的具名變數,那就做不了NRVO了)。

具體可以看這個:

Copy elision - cppreference.com

通常你應該盡量做到讓編譯器來完成copy elision,而不是依賴std::move來迴避複製,因為移動構造的代價不一定真的很小(比如std::array的移動複製代價就是O(N)而不是O(1))。


準確來說需要的不僅是右值引用而是移動構造函數,還要類型本身適合移動。返回一個龐大的 POD 類對象也是不太舒服的。

另外也應該考慮下能否利用 RVO/NRVO ,C++17 中 RVO 變為強制,而且允許返回類型沒有複製和移動構造函數。


如果需要返回大數據結構對象可以考慮NRV優化,右值引用配合std::move對大字元串確實有效,不過自己定義的類要想利用右值引用和move就要在數據數據時考慮pimpl。


沒有右值引用的時候也可以啊,編譯器有優化的,copy elision

再大的結構都可以直接返回,不會拷貝,類似emplace


右值引用只是個修飾符,和cv一樣,用來表示變數是臨時量。

具體使用還得需要程序員手工重載對應的函數。

而且右值比rvo優化,多了一次右值拷貝,一次析構函數。


其他答案已經說了複製消除(copy elision),我就講一下基本原理:

首先機器層面返回不了結構,都是隱式傳指針進去寫,

然後,不管你是「 t foo; return foo;」還是直接「 return foo();」,都會直接從傳進去的那個指針來構造,

最後,如果你還不信,可以動手試驗一下,你會發現並沒有調用拷貝或是移動構造函數。


推薦閱讀:

C++ 研發實習生面試通常會被問到什麼問題?
怎麼返回容器中部分內容的引用?
C++中將一個成員函數定義為const的會有助於提高性能嗎?
C++LNK2019錯誤如何解決?

TAG:C |