編譯器選擇
如果想自己實踐rvo和nrvo,不要在vs下嘗試(這裡的vs不是指vs code),用支援g++的編譯器去測試(我這裡用的是mingw)。因為vs無論在debug還是release下都是無法關閉rvo優化的,dubug下可以關閉nrvo優化。而g++預設都是執行nrv0優化的。
rvo/nrvo
rvo(return value optimization,返回值優化),而nrvo是(named return value optimization)。他們的作用就是:當函式需要返回乙個物件的時候,如果自己建立乙個臨時物件使用者返回,那麼這個臨時物件會消耗乙個建構函式的呼叫、乙個拷貝建構函式的呼叫以及乙個析構函式的呼叫的代價。而如果稍微做一點優化,就可以將成本降低到乙個建構函式的代價,也就是將內容直接構造到左值中,中間不生成臨時變數。
我們拿下面的程式來分析rvo和nrvo優化情況。
class
test
;int test::num =0;
test::
test()
test::
test
(const test& rhs)
test& test::
operator=(
const test& rhs)
test::
~test()
test fun1()
test fun2()
intmain()
不執行rvo和nrvo優化
前面說了,在vs2017下是無法關閉兩個優化的,在g++下可以通過-fno-elide-constructors來關閉。
// 關閉rvo優化,test t2 = fun2() 執行結果
do constructor function and num =
1// test()生成乙個臨時物件tmp1
do copy constructor function and num =
2// return時,再拷貝乙個臨時物件tmp2
do destructor function and num =
1// 函式退出時,tmp1銷毀
do copy constructor function and num =
2// 拷貝初始化t2
do destructor function and num =
1// tmp2銷毀
do destructor function and num =
0// t2銷毀
// 關閉nrvo優化,test t1 = fun1() 執行結果
do constructor function and num =
1// 生成區域性物件tmp
do copy constructor function and num =
2// return時需要拷貝這個tmp,假設為tmp1
do destructor function and num =
1// 函式退出時,銷毀tmp
do copy constructor function and num =
2// 用tmp1, 構造t1
do destructor function and num =
1// 銷毀tmp1
do destructor function and num =
0// 銷毀t
只執行rvo優化
前面說了,vs2017在debug下是關閉nrvo優化的。
// 只進行rvo優化,test t2 = fun2() 執行結果
do constructor function and num =
1do destructor function and num =
0// 只進行rvo優化,test t1 = fun1() 執行結果
do constructor function and num =
1do copy constructor function and num =
2do destructor function and num =
1do destructor function and num =
0
從上面結果可以看到,若進行rvo優化,fun2()中生成的匿名物件直接初始化了t2,只做了一次構造和析構,相比於不做rv0優化,少了4次構造/析構;而只進行rvo優化,fun1()中先生成了tmp臨時物件,然後返回時用這個臨時物件拷貝初始化了t1,可見rvo初始化也起到了作用。rvo優化相當於將t1/t2物件的位址傳到函式中,省去了函式退出的拷貝和析構。
只進行nrvo優化
我理解的nrvo其實就是rvo,所以沒有只進行nrvo優化的。g++提供的關閉返回值優化命令,是將rvo和nrvo都關了。(這裡理解若不對,請告知我,謝謝!)
進行rvo和nrvo優化
g++在預設情況都是開這兩個優化的,vs2017在release下也是開這兩個優化。
// 同時進行rvo和nrvo優化,t1 = fun1() 結果:
do constructor function and num =
1do destructor function and num =
0// 同時進行rvo和nrvo優化,t2 = fun2() 結果:
do constructor function and num =
1do destructor function and num =
0
可以看出nrvo優化在rvo上更近一步。
哪些情況rvo/nrvo優化不執行
除了上面提到的顯式禁止,或者debug/release來禁止優化外,還有哪些情況優化不執行:
(1)函式外已經有乙個已經的物件
test fun2()
intmain()
// 優化後的結果:
do constructor function and num =
1do constructor function and num =
2do assignment constructor function and num =
3do destructor function and num =
2do destructor function and num =
1
(2)有多個分支返回不同物件
test fun1()
intmain()
// 優化後的結果:
do constructor function and num =
1do constructor function and num =
2do copy constructor function and num =
3do destructor function and num =
2do destructor function and num =
1do destructor function and num =
0
參考資料 C 編譯器優化之RVO
寫這篇文章純屬意外收穫.先看一段 在這段 中定義了建構函式,拷貝建構函式,移動建構函式,賦值構造,移動賦值構造,以及析構函式.include using namespace std classaa const a a a a a a operator const a a else return th...
C 中的RVO優化和NRVO優化
rvo return value optimization 和nrvo named return value optimization 是c 在處理乙個函式返回類物件並將返回值賦給另乙個物件時,為了減少拷貝構造次數以及析構次數而採用的一種編譯器優化技術。本篇部落格以 深度探索c 物件模型 中例子來總...
C 中的RVO和NRVO優化
rvo return value optimization 和nrvo named return value optimization 是c 在處理乙個函式返回類物件並將返回值賦給另乙個物件時,為了減少拷貝構造次數以及析構次數而採用的一種編譯器優化技術。本篇部落格以 深度探索c 物件模型 中例子來總...