讓我們考慮最簡單的例子:
lofactory(...).some_method();
在這種情況下,一個副本來自到呼叫者上下文的lofactory可能是–,但它可以通過RVO/NRVO進行優化。
LargeObject mylo2 (lofactory(...));
在這種情況下可能的副本:
- 返回臨時從lofactory至呼叫者上下文–可以通過RVO/NRVO
- 禁止複製被優化掉構建mylo2 from 臨時 –可以通過複製省音
const LargeObject& mylo1 = lofactory(...);
被優化掉在這種情況下,存在一個拷貝仍然是可能的:
- 返回臨時從lofactory來電上下文–可以優化啊y由RVO/NRVO(太!)
引用將綁定到此臨時。
所以,
是否有任何普遍接受的規則或最佳做法時使用常量&來臨時變量,當依靠RVO/NRVO?
正如我上面所說的,即使是在與一個const&
情況下,unnecesary複製是可能的,並且它可以通過RVO/NRVO被優化掉。
如果您的編譯器在某些情況下應用了RVO/NVRO,那麼很可能它會在第2階段(上圖)進行復制刪除。因爲在這種情況下,copy-elision比NRVO簡單得多。
但是,在最壞的情況下,您將有一個副本用於const&
的情況,當您初始化該值時將有兩個副本。
難道會出現這樣的情況:使用const &方法比不使用它更糟嗎?
我不認爲有這種情況。至少除非你的編譯器使用奇怪的規則來區分const&
。 (對於類似情況的例子,我注意到,MSVC沒有爲集合初始化做NVRO。)
(我在想例如約C++ 11移動語義如果LargeObject那些已經實施... )
在C++ 11,如果LargeObject
有移動的語義,那麼在最壞的情況下,你會當你初始化值必須爲const&
情況下,一個舉動,和兩個動作。所以,const&
還是好一點。
所以,一個好的規則將始終綁定臨時變量如果可能的話爲const &,因爲它可能會導致一個副本,如果編譯器不能做一個副本,省音出於某種原因?
不知道應用程序的實際上下文,這似乎是一個很好的規則。
在C++ 11中,可以將臨時值與右值引用綁定 - LargeObject & &。所以,這樣的臨時可以修改。
順便說一下,移動語義仿真可以通過不同的技巧向C++ 98/03提供。例如:
但是,即使存在移動語義 - 有一些對象不能被低價移動。例如,4×4的矩陣類裏面有雙數據[4] [4]。因此,即使在C++ 11中,Copy-elision RVO/NRVO仍然非常重要。順便提一下,Copy-elision/RVO/NRVO發生時 - 比移動更快。
PS,在現實情況下,也有一些需要考慮的其他注意事項:
舉例來說,如果你有函數返回向量,即使移動/ RVO/NRVO /複製,省音會應用 - 它仍然可能不是100%效率。例如,考慮以下情況:
while(/*...*/)
{
vector<some> v = produce_next(/* ... */); // Move/RVO/NRVO are applied
// ...
}
這將是更有效地更改代碼:
vector<some> v;
while(/*...*/)
{
v.clear();
produce_next(v); // fill v
// or something like:
produce_next(back_inserter(v));
// ...
}
因爲在這種情況下,內部矢量已分配的內存,可以當v.capacity重新使用()就足夠了,不需要在每次迭代時在produce_next中進行新的分配。
因此,如果可能的話,_always_將臨時對象綁定到'const&',因爲如果編譯器由於某種原因未能進行復制elision,它可能會阻止拷貝? –
已接受,謝謝! –