詳解C++編譯器優(yōu)化技術(shù)
前言
注1:vc6、vs沒有提供編譯選項來關(guān)閉該優(yōu)化,無論是debug還是release都會進(jìn)行RVO和復(fù)制省略優(yōu)化
注2:vc6、vs2005以下及vs2005+ Debug上不支持NRVO優(yōu)化,vs2005+ Release支持NRVO優(yōu)化
注3:g++支持這三種優(yōu)化,并且可通過編譯選項:-fno-elide-constructors來關(guān)閉優(yōu)化
RVO
#include <stdio.h> class A { public: A() { printf("%p construct\n", this); } A(const A& cp) { printf("%p copy construct\n", this); } ~A() { printf("%p destruct\n", this); } }; A GetA() { return A(); } int main() { { A a = GetA(); } return 0; }
在g++和vc6、vs中,上述代碼僅僅只會調(diào)用一次構(gòu)造函數(shù)和析構(gòu)函數(shù) ,輸出結(jié)果如下:
0x7ffe9d1edd0f construct
0x7ffe9d1edd0f destruct
在g++中,加上-fno-elide-constructors選項關(guān)閉優(yōu)化后,輸出結(jié)果如下:
0x7ffc46947d4f construct // 在函數(shù)GetA中,調(diào)用無參構(gòu)造函數(shù)A()構(gòu)造出一個臨時變量temp
0x7ffc46947d7f copy construct // 函數(shù)GetA return語句處,把臨時變量temp做為參數(shù)傳入并調(diào)用拷貝構(gòu)造函數(shù)A(const A& cp)將返回值ret構(gòu)造出來
0x7ffc46947d4f destruct // 函數(shù)GetA執(zhí)行完return語句后,臨時變量temp生命周期結(jié)束,調(diào)用其析構(gòu)函數(shù)~A()
0x7ffc46947d7e copy construct // 函數(shù)GetA調(diào)用結(jié)束,返回上層main函數(shù)后,把返回值變量ret做為參數(shù)傳入并調(diào)用拷貝構(gòu)造函數(shù)A(const A& cp)將變量A a構(gòu)造出來
0x7ffc46947d7f destruct // A a = GetA()語句結(jié)束后,返回值ret生命周期結(jié)束,調(diào)用其析構(gòu)函數(shù)~A()
0x7ffc46947d7e destruct // A a要離開作用域,生命周期結(jié)束,調(diào)用其析構(gòu)函數(shù)~A()
注:臨時變量temp、返回值ret均為匿名變量
下面用c++代碼模擬一下其優(yōu)化行為:
#include <new> A& GetA(void* p) { //由于p的內(nèi)存是從外部傳入的,函數(shù)返回后仍然有效,因此返回值可為A& //vs中,以下代碼還可以寫成: // A& o = *((A*)p); // o.A::A(); // return o; return *new (p) A(); // placement new } int main() { { char buf[sizeof(A)]; A& a = GetA(buf); a.~A(); } return 0; }
NRVO
g++編譯器、vs2005+ Release(開啟/O2及以上優(yōu)化開關(guān))
修改上述代碼,將GetA的實現(xiàn)修改成:
A GetA() { A o; return o; }
在g++、vs2005+ Release中,上述代碼也僅僅只會調(diào)用一次構(gòu)造函數(shù)和析構(gòu)函數(shù) ,輸出結(jié)果如下:
0x7ffe9d1edd0f construct
0x7ffe9d1edd0f destruct
g++加上-fno-elide-constructors選項關(guān)閉優(yōu)化后,和上述結(jié)果一樣
0x7ffc46947d4f construct
0x7ffc46947d7f copy construct
0x7ffc46947d4f destruct
0x7ffc46947d7e copy construct
0x7ffc46947d7f destruct
0x7ffc46947d7e destruct
但在vc6、vs2005以下、vs2005+ Debug中,沒有進(jìn)行NRVO優(yōu)化,輸出結(jié)果為:
18fec4 construct // 在函數(shù)GetA中,調(diào)用無參構(gòu)造函數(shù)A()構(gòu)造出一個臨時變量o
18ff44 copy construct // 函數(shù)GetA return語句處,把臨時變量o做為參數(shù)傳入并調(diào)用拷貝構(gòu)造函數(shù)A(const A& cp)將返回值ret構(gòu)造出來
18fec4 destruct // 函數(shù)GetA執(zhí)行完return語句后,臨時變量o生命周期結(jié)束,調(diào)用其析構(gòu)函數(shù)~A()
18ff44 destruct // A a要離開作用域,生命周期結(jié)束,調(diào)用其析構(gòu)函數(shù)~A()
下面用c++代碼模擬一下vc6、vs2005以下、vs2005+ Debug上的行為:
#include <new> A& GetA(void* p) { A o; //由于p的內(nèi)存是從外部傳入的,函數(shù)返回后仍然有效,因此返回值可為A& //vs中,以下代碼還可以寫成: // A& t = *((A*)p); // t.A::A(o); // return t; return *new (p) A(o); // placement new } int main() { { char buf[sizeof(A)]; A& a = GetA(buf); a.~A(); } return 0; }
注:與g++、vs2005+ Release相比,vc6、vs2005以下、vs2005+ Debug只優(yōu)化掉了返回值到變量a的拷貝,命名局部變量o沒有被優(yōu)化掉,所以最后一共有2次構(gòu)造和析構(gòu)的調(diào)用
復(fù)制省略
典型情況是:調(diào)用構(gòu)造函數(shù)進(jìn)行值類型傳參
void Func(A a) { } int main() { { Func(A()); } return 0; }
在g++和vc6、vs中,上述代碼僅僅只會調(diào)用一次構(gòu)造函數(shù)和析構(gòu)函數(shù) ,輸出結(jié)果如下:
0x7ffeb5148d0f construct
0x7ffeb5148d0f destruct
在g++中,加上-fno-elide-constructors選項關(guān)閉優(yōu)化后,輸出結(jié)果如下:
0x7ffc53c141ef construct // 在main函數(shù)中,調(diào)用無參構(gòu)造函數(shù)構(gòu)造實參變量o
0x7ffc53c141ee copy construct // 調(diào)用Func函數(shù)后,將實參變量o做為參數(shù)傳入并調(diào)用拷貝構(gòu)造函數(shù)A(const A& cp)將形參變量a構(gòu)造出來
0x7ffc53c141ee destruct // 函數(shù)Func執(zhí)行完后,形參變量a生命周期結(jié)束,調(diào)用其析構(gòu)函數(shù)~A()
0x7ffc53c141ef destruct // 返回main函數(shù)后,實參變量o要離開作用域,生命周期結(jié)束,調(diào)用其析構(gòu)函數(shù)~A()
下面用c++代碼模擬一下其優(yōu)化行為:
void Func(const A& a) { } int main() { { Func(A()); } return 0; }
優(yōu)化失效的情況
開啟g++優(yōu)化,得到以下各種失效情況的輸出結(jié)果:
(1)根據(jù)不同的條件分支,返回不同變量
A GetA(bool bflag) { A a1, a2; if (bflag) return a1; return a2; } int main() { A a = GetA(true); return 0; }
0x7ffc3cca324f construct
0x7ffc3cca324e construct
0x7ffc3cca327f copy construct
0x7ffc3cca324e destruct
0x7ffc3cca324f destruct
0x7ffc3cca327f destruct
注1:2次缺省構(gòu)造函數(shù)調(diào)用:用于構(gòu)造a1、a2
注2:1次拷貝構(gòu)造函數(shù)調(diào)用:用于拷貝構(gòu)造返回值
注3:這兒仍然用右值引用優(yōu)化掉了一次拷貝函數(shù)調(diào)用:返回值賦值給a
(2)返回參數(shù)變量
(3)返回全局變量
(4)返回復(fù)合數(shù)據(jù)類型中的成員變量
(5)返回值賦值給已構(gòu)造好的變量(此時會調(diào)用operator==賦值運(yùn)算符)
以上就是詳解C++編譯器優(yōu)化技術(shù)的詳細(xì)內(nèi)容,更多關(guān)于C++編譯器優(yōu)化技術(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語言數(shù)據(jù)結(jié)構(gòu)之單向鏈表詳解
單向鏈表(單鏈表)是鏈表的一種,其特點是鏈表的鏈接方向是單向的,對鏈表的訪問要通過順序讀取從頭部開始。本文將為大家詳細(xì)講講單向鏈表的實現(xiàn)與使用,需要的可以參考一下2022-08-08基于C++11的threadpool線程池(簡潔且可以帶任意多的參數(shù))
C++11 加入了線程庫,從此告別了標(biāo)準(zhǔn)庫不支持并發(fā)的歷史。然而 c++ 對于多線程的支持還是比較低級,稍微高級一點的用法都需要自己去實現(xiàn),譬如線程池、信號量等2019-04-04C語言實現(xiàn)超市信息管理系統(tǒng)課程設(shè)計
這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)超市信息管理系統(tǒng)課程設(shè)計,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03Qt數(shù)據(jù)庫應(yīng)用之實現(xiàn)通用數(shù)據(jù)生成器
有兩種應(yīng)用場景需要用到數(shù)據(jù)生成器,一種是需要測試數(shù)據(jù)庫性能,一種是隨機(jī)模擬生成一堆數(shù)據(jù),用來測試程序的性能。本文將利用Qt實現(xiàn)通用數(shù)據(jù)生成器,需要的可以參考一下2022-02-02淺析Boost智能指針:scoped_ptr shared_ptr weak_ptr
雖然通過弱引用指針可以有效的解除循環(huán)引用,但這種方式必須在程序員能預(yù)見會出現(xiàn)循環(huán)引用的情況下才能使用,也可以是說這個僅僅是一種編譯期的解決方案,如果程序在運(yùn)行過程中出現(xiàn)了循環(huán)引用,還是會造成內(nèi)存泄漏的2013-09-09