詳解C++編譯器優(yōu)化技術(shù)
前言
注1:vc6、vs沒(méi)有提供編譯選項(xiàng)來(lái)關(guān)閉該優(yōu)化,無(wú)論是debug還是release都會(huì)進(jìn)行RVO和復(fù)制省略?xún)?yōu)化
注2:vc6、vs2005以下及vs2005+ Debug上不支持NRVO優(yōu)化,vs2005+ Release支持NRVO優(yōu)化
注3:g++支持這三種優(yōu)化,并且可通過(guò)編譯選項(xiàng):-fno-elide-constructors來(lái)關(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中,上述代碼僅僅只會(huì)調(diào)用一次構(gòu)造函數(shù)和析構(gòu)函數(shù) ,輸出結(jié)果如下:
0x7ffe9d1edd0f construct
0x7ffe9d1edd0f destruct
在g++中,加上-fno-elide-constructors選項(xiàng)關(guān)閉優(yōu)化后,輸出結(jié)果如下:
0x7ffc46947d4f construct // 在函數(shù)GetA中,調(diào)用無(wú)參構(gòu)造函數(shù)A()構(gòu)造出一個(gè)臨時(shí)變量temp
0x7ffc46947d7f copy construct // 函數(shù)GetA return語(yǔ)句處,把臨時(shí)變量temp做為參數(shù)傳入并調(diào)用拷貝構(gòu)造函數(shù)A(const A& cp)將返回值ret構(gòu)造出來(lái)
0x7ffc46947d4f destruct // 函數(shù)GetA執(zhí)行完return語(yǔ)句后,臨時(shí)變量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)造出來(lái)
0x7ffc46947d7f destruct // A a = GetA()語(yǔ)句結(jié)束后,返回值ret生命周期結(jié)束,調(diào)用其析構(gòu)函數(shù)~A()
0x7ffc46947d7e destruct // A a要離開(kāi)作用域,生命周期結(jié)束,調(diào)用其析構(gòu)函數(shù)~A()
注:臨時(shí)變量temp、返回值ret均為匿名變量
下面用c++代碼模擬一下其優(yōu)化行為:
#include <new>
A& GetA(void* p)
{
//由于p的內(nèi)存是從外部傳入的,函數(shù)返回后仍然有效,因此返回值可為A&
//vs中,以下代碼還可以寫(xiě)成:
// 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(開(kāi)啟/O2及以上優(yōu)化開(kāi)關(guān))
修改上述代碼,將GetA的實(shí)現(xiàn)修改成:
A GetA()
{
A o;
return o;
}
在g++、vs2005+ Release中,上述代碼也僅僅只會(huì)調(diào)用一次構(gòu)造函數(shù)和析構(gòu)函數(shù) ,輸出結(jié)果如下:
0x7ffe9d1edd0f construct
0x7ffe9d1edd0f destruct
g++加上-fno-elide-constructors選項(xiàng)關(guān)閉優(yōu)化后,和上述結(jié)果一樣
0x7ffc46947d4f construct
0x7ffc46947d7f copy construct
0x7ffc46947d4f destruct
0x7ffc46947d7e copy construct
0x7ffc46947d7f destruct
0x7ffc46947d7e destruct
但在vc6、vs2005以下、vs2005+ Debug中,沒(méi)有進(jìn)行NRVO優(yōu)化,輸出結(jié)果為:
18fec4 construct // 在函數(shù)GetA中,調(diào)用無(wú)參構(gòu)造函數(shù)A()構(gòu)造出一個(gè)臨時(shí)變量o
18ff44 copy construct // 函數(shù)GetA return語(yǔ)句處,把臨時(shí)變量o做為參數(shù)傳入并調(diào)用拷貝構(gòu)造函數(shù)A(const A& cp)將返回值ret構(gòu)造出來(lái)
18fec4 destruct // 函數(shù)GetA執(zhí)行完return語(yǔ)句后,臨時(shí)變量o生命周期結(jié)束,調(diào)用其析構(gòu)函數(shù)~A()
18ff44 destruct // A a要離開(kāi)作用域,生命周期結(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中,以下代碼還可以寫(xiě)成:
// 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沒(méi)有被優(yōu)化掉,所以最后一共有2次構(gòu)造和析構(gòu)的調(diào)用
復(fù)制省略
典型情況是:調(diào)用構(gòu)造函數(shù)進(jìn)行值類(lèi)型傳參
void Func(A a)
{
}
int main()
{
{
Func(A());
}
return 0;
}
在g++和vc6、vs中,上述代碼僅僅只會(huì)調(diào)用一次構(gòu)造函數(shù)和析構(gòu)函數(shù) ,輸出結(jié)果如下:
0x7ffeb5148d0f construct
0x7ffeb5148d0f destruct
在g++中,加上-fno-elide-constructors選項(xiàng)關(guān)閉優(yōu)化后,輸出結(jié)果如下:
0x7ffc53c141ef construct // 在main函數(shù)中,調(diào)用無(wú)參構(gòu)造函數(shù)構(gòu)造實(shí)參變量o
0x7ffc53c141ee copy construct // 調(diào)用Func函數(shù)后,將實(shí)參變量o做為參數(shù)傳入并調(diào)用拷貝構(gòu)造函數(shù)A(const A& cp)將形參變量a構(gòu)造出來(lái)
0x7ffc53c141ee destruct // 函數(shù)Func執(zhí)行完后,形參變量a生命周期結(jié)束,調(diào)用其析構(gòu)函數(shù)~A()
0x7ffc53c141ef destruct // 返回main函數(shù)后,實(shí)參變量o要離開(kāi)作用域,生命周期結(jié)束,調(diào)用其析構(gòu)函數(shù)~A()
下面用c++代碼模擬一下其優(yōu)化行為:
void Func(const A& a)
{
}
int main()
{
{
Func(A());
}
return 0;
}
優(yōu)化失效的情況
開(kāi)啟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ù)類(lèi)型中的成員變量
(5)返回值賦值給已構(gòu)造好的變量(此時(shí)會(huì)調(diào)用operator==賦值運(yùn)算符)
以上就是詳解C++編譯器優(yōu)化技術(shù)的詳細(xì)內(nèi)容,更多關(guān)于C++編譯器優(yōu)化技術(shù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
win10+VS2017+Cuda10.0環(huán)境配置詳解
這篇文章主要介紹了win10+VS2017+Cuda10.0環(huán)境配置詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
c++如何實(shí)現(xiàn)跳表(skiplist)
這篇文章主要介紹了c++如何實(shí)現(xiàn)跳表,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-08-08
C++?STL標(biāo)準(zhǔn)庫(kù)std::vector擴(kuò)容時(shí)進(jìn)行深復(fù)制原因詳解
我們知道,std::vector之所以可以動(dòng)態(tài)擴(kuò)容,同時(shí)還可以保持順序存儲(chǔ),主要取決于其擴(kuò)容復(fù)制的機(jī)制。當(dāng)容量滿(mǎn)時(shí),會(huì)重新劃分一片更大的內(nèi)存區(qū)域,然后將所有的元素拷貝過(guò)去2022-08-08
codeblocks 對(duì)‘cv::waitKey(int)’未定義的引用方式
今天小編就為大家分享一篇codeblocks 對(duì)‘cv::waitKey(int)’未定義的引用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-12-12
如何調(diào)用C標(biāo)準(zhǔn)庫(kù)的exit函數(shù)詳解
這篇文章主要給大家介紹了關(guān)于如何調(diào)用C標(biāo)準(zhǔn)庫(kù)的exit函數(shù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
C/C++雜記 虛函數(shù)的實(shí)現(xiàn)的基本原理(圖文)
這篇文章主要介紹了C/C++雜記 虛函數(shù)的實(shí)現(xiàn)的基本原理(圖文),需要的朋友可以參考下2016-06-06
C++中關(guān)于[]靜態(tài)數(shù)組和new分配的動(dòng)態(tài)數(shù)組的區(qū)別分析
這篇文章主要介紹了C++中關(guān)于[]靜態(tài)數(shù)組和new分配的動(dòng)態(tài)數(shù)組的區(qū)別分析,很重要的概念,需要的朋友可以參考下2014-08-08

