編譯器優化RVO和NRVO

2021-10-01 12:49:36 字數 3607 閱讀 5268

編譯器選擇

如果想自己實踐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 物件模型 中例子來總...