新聞中心
本文的主要內(nèi)容如下圖所示:

函數(shù)返回機制
既然本文的主題是返回值優(yōu)化,那么就不得不提一下函數(shù)返回值在編譯器中的實現(xiàn)機制,這樣以便更好的理解本文內(nèi)容。
函數(shù)返回值的傳遞分為兩種情況:
當(dāng)返回的對象大小不超過8字節(jié)時,通過寄存器(eax edx)返回
當(dāng)返回的對象大小大于8字節(jié)時,通過棧返回。此處需要注意的時候,如果返回的是struct或者class對象,即使其大小不大于8字節(jié),也是通過棧返回的。
在通過棧返回的時候,棧上會有一塊空間來保存函數(shù)的返回值。當(dāng)函數(shù)結(jié)束的時候,會把要返回的對象拷貝到這塊區(qū)域,對于內(nèi)置類型是直接拷貝,類類型的話是調(diào)用拷貝構(gòu)造函數(shù)。這塊區(qū)域又稱為函數(shù)返回的臨時對象。
示例
為了能夠方便通過輸出理解程序的運行情況,本文中所有的代碼示例均如下類所示:
class Obj {
public:
Obj() { // 構(gòu)造函數(shù)
std::cout << "in Obj() " << " " << this << std::endl;
}
Obj(int n) {
std::cout << "in Obj(int) " << " " << this << std::endl;
}
Obj(const Obj &obj) { // 拷貝構(gòu)造函數(shù)
std::cout << "in Obj(const Obj &obj) " << &obj << " " << this << std::endl;
}
Obj &operator=(const Obj &obj) { // 賦值構(gòu)造函數(shù)
std::cout << "in operator=(const Obj &obj)" << std::endl;
return *this;
}
~Obj() { // 析構(gòu)函數(shù)
std::cout << "in ~Obj() " << this << std::endl;
}
int n;
};
在本示例代碼中
- 在各個函數(shù)中均加入了函數(shù)名稱輸出,以方便了解函數(shù)的調(diào)用情況
- 各個函數(shù)中加入了對象指針地址輸出,以方便了解構(gòu)造、拷貝以及賦值等情況
禁用優(yōu)化
為了提升程序的性能,編譯器在某些情況下,會對我們的代碼進行優(yōu)化,為了搞清楚編譯都做了哪些優(yōu)化,我們首先在禁用優(yōu)化的情況下,看看程序的。
首先,我們看一段代碼,如下:
Obj fun() {
Obj obj;
// do sth;
return obj;
}
int main() {
Obj obj = fun();
std::cout << "&obj is " << &obj << std::endl;
return 0;
}
現(xiàn)在,撇開編譯器優(yōu)化,我們單純從上面代碼進行分析,調(diào)用的Obj類成員函數(shù)的順序應(yīng)該為:
- 調(diào)用構(gòu)造函數(shù),生成對象
- 調(diào)用拷貝構(gòu)造函數(shù),生成臨時對象
- 析構(gòu)第1步生成的對象
- 調(diào)用拷貝構(gòu)造函數(shù),將第2步生成的臨時變量拷貝到main()函數(shù)中的局部對象obj中
- 調(diào)用析構(gòu)函數(shù),釋放第2步生成的臨時對象
- 調(diào)用析構(gòu)函數(shù),釋放main()函數(shù)中的obj局部對象
為了驗證我們所理解的順序是否跟程序運行結(jié)果一致,編譯并運行,結(jié)果如下:
g++ -g -std=c++11 test.cc -o test && ./test
in Obj() 0x7ffd6fb15240
&obj is 0x7ffd6fb15240
in ~Obj() 0x7ffd6fb15240
輸出結(jié)果與我們預(yù)期差別很大,是不是懷疑之前的理解是錯誤的?其實這是因為編譯器對函數(shù)返回值做了優(yōu)化導(dǎo)致。
編譯器提供了個編譯選項-fno-elide-constructors來禁用返回值優(yōu)化,編譯并運行之后,輸出如下:
g++ -std=c++11 -fno-elide-constructors -g test.cc -o test && ./test
in Obj() 0x7ffee18a9a00 // 在fun()函數(shù)中,構(gòu)造obj對象
in Obj(const Obj &obj) 0x7ffee18a9a00 0x7ffee18a9a40 // 通過拷貝構(gòu)造創(chuàng)建臨時變量(fun()函數(shù)定義的obj--->臨時對象)
in ~Obj() 0x7ffee18a9a00 // 析構(gòu)fun()函數(shù)中構(gòu)造的obj對象(fun()函數(shù)定義的obj)
in Obj(const Obj &obj) 0x7ffee18a9a40 0x7ffee18a9a30 // 通過拷貝構(gòu)造函數(shù)構(gòu)建obj(main函數(shù)中的)對象(臨時對象--->main()函數(shù)定義的obj)
in ~Obj() 0x7ffee18a9a40 // 釋放臨時對象
&obj is 0x7ffee18a9a30
in ~Obj() 0x7ffee18a9a30 // 釋放main()函數(shù)中定義的obj對象
上述輸出結(jié)果跟我們之前的理解一致了吧。
通過上述示例可以看出,如果編譯器沒有進行返回值優(yōu)化,則一個 簡單的拷貝賦值行為,總共調(diào)用了6次,分別為1次構(gòu)造函數(shù),2次拷貝構(gòu)造函數(shù),以及3次析構(gòu)函數(shù)。而如果做了優(yōu)化之后呢,只調(diào)用了1次構(gòu)造函數(shù)和1次析構(gòu)函數(shù),相比起來,優(yōu)化的程度非常高。
當(dāng)一個函數(shù)返回一個對象實例的時候,理論上會產(chǎn)生臨時變量,那必然會導(dǎo)致新對象的構(gòu)造和舊對象的析構(gòu),這對性能是有影響的。C++標(biāo)準(zhǔn)允許省略拷貝構(gòu)造函數(shù)。簡單來說,就是在調(diào)用的地方,將需要初始化對象的引用作為函數(shù)參數(shù)傳遞給函數(shù),進而避免不必要的拷貝。
編譯器對函數(shù)返回值優(yōu)化的方式分為RVO和NRVO(自c++11開始引入),在后面的文章中,我們將對該兩種方式進行詳細分析。
在此需要說明的是,因為自C++11起才引入了NRVO,而NRVO針對的是具名函數(shù)對象返回,而C++11之前的RVO相對NRVO來說,是一種URVO(未具名返回值優(yōu)化)
RVO
RVO(Return Value Optimization),是一種編譯器優(yōu)化技術(shù),通過該技術(shù),編譯器可以減少函數(shù)返回時生成臨時對象的個數(shù),從某種程度上可以提高程序的運行效率,對需要分配大量內(nèi)存的類對象其值復(fù)制過程十分友好。
當(dāng)一個未具名且未綁定到任何引用的臨時變量被移動或復(fù)制到一個相同的對象時,拷貝和移動構(gòu)造可以被省略。當(dāng)這個臨時對象在被構(gòu)造的時候,他會直接被構(gòu)造在將要拷貝/移動到的對象。當(dāng)未命名臨時對象是函數(shù)返回值時,發(fā)生的省略拷貝的行為被稱為RVO(返回值優(yōu)化)。
RVO優(yōu)化針對的是返回一個未具名對象,也就是說RVO的功能是消除函數(shù)返回時創(chuàng)建的臨時對象。
Obj fun() {
return Obj();
}
int main() {
Obj obj = fun();
std::cout << "&obj is " << &obj << std::endl;
return 0;
}
為了理解編譯所做的優(yōu)化,我們首先禁用RVO優(yōu)化,輸出如下:
in Obj() 0x7ffd9bd8ab30 // 在fun()函數(shù)中,構(gòu)造obj對象
in Obj(const Obj &obj) 0x7ffd9bd8ab30 0x7ffd9bd8ab70 // // 通過拷貝構(gòu)造創(chuàng)建臨時變量(fun()函數(shù)定義的obj--->臨時對象)
in ~Obj() 0x7ffd9bd8ab30 // // 析構(gòu)fun()函數(shù)中構(gòu)造的obj對象(fun()函數(shù)定義的obj)
in Obj(const Obj &obj) 0x7ffd9bd8ab70 0x7ffd9bd8ab60 // // 通過拷貝構(gòu)造函數(shù)構(gòu)建obj(main函數(shù)中的)對象(臨時對象--->main()函數(shù)定義的obj)
in ~Obj() 0x7ffd9bd8ab70 // 釋放臨時對象
&obj is 0x7ffd9bd8ab60
in ~Obj() 0x7ffd9bd8ab60 // 釋放main()函數(shù)中定義的obj對象
從上述輸出,我們可以看出,上述代碼總共調(diào)用了1次構(gòu)造函數(shù)、2次拷貝構(gòu)造函數(shù)以及3次析構(gòu)函數(shù)。
下面,我們?nèi)サ艚脙?yōu)化的選項,重新編譯運行,輸出如下:
in Obj() 0x7ffcc33536e0
&obj is 0x7ffcc33536e0
in ~Obj() 0x7ffcc33536e0
可以看出,經(jīng)過編譯器優(yōu)化之后,總共調(diào)用了1次構(gòu)造函數(shù),一次拷貝構(gòu)造函數(shù)。
那么,編譯器優(yōu)化后與優(yōu)化前相比,減少了2次拷貝構(gòu)造函數(shù)以及兩次析構(gòu)函數(shù)。
編譯器明確知道函數(shù)會返回哪一個局部對象,那么編譯器會把存儲這個局部對象的地址和存儲返回臨時對象的地址進行復(fù)用,也就是說避免了從局部對象到臨時對象的拷貝操作,這就是RVO。
可以通過-fno-elide-constructors來禁用RVO。
NRVO
NRVO,又名具名返回值優(yōu)化(Named Return Value Optimization),為RVO的一個變種,也是一種編譯器對于函數(shù)返回值優(yōu)化的方式。此特性從C++11開始支持,也就是說C++98、C++03都是沒有將此優(yōu)化特性寫到標(biāo)準(zhǔn)中的,與RVO的不同之處在于函數(shù)返回的臨時值是具名的。
NRVO與RVO的區(qū)別是返回的對象是具名的,既然返回的對象是具名的,那么對象是在return語句之前就構(gòu)造完成。
我們?nèi)匀灰砸粋€例子來分析編譯器的NRVO都做了哪些優(yōu)化。
Obj fun() {
Obj obj; // 具名對象
// do sth;
return obj;
}
int main() {
Obj obj = fun();
std::cout << "&obj is " << &obj << std::endl;
return 0;
}
通過-fno-elide-constructors禁用編譯器優(yōu)化之后,輸出如下:
in Obj() 0x7ffee18a9a00 // 在fun()函數(shù)中,構(gòu)造obj對象
in Obj(const Obj &obj) 0x7ffee18a9a00 0x7ffee18a9a40 // 通過拷貝構(gòu)造創(chuàng)建臨時變量(fun()函數(shù)定義的obj--->臨時對象)
in ~Obj() 0x7ffee18a9a00 // 析構(gòu)fun()函數(shù)中構(gòu)造的obj對象(fun()函數(shù)定義的obj)
in Obj(const Obj &obj) 0x7ffee18a9a40 0x7ffee18a9a30 // 通過拷貝構(gòu)造函數(shù)構(gòu)建obj(main函數(shù)中的)對象(臨時對象--->main()函數(shù)定義的obj)
in ~Obj() 0x7ffee18a9a40 // 釋放臨時對象
&obj is 0x7ffee18a9a30
in ~Obj() 0x7ffee18a9a30 // 釋放main()函數(shù)中定義的obj對象
從上述輸出,我們可以看出,總共1次構(gòu)造函數(shù),2次拷貝構(gòu)造函數(shù),以及3次析構(gòu)函數(shù)。
如果啟用編譯器返回值優(yōu)化后,輸出如下:
in Obj() 0x7ffd9e16b2b0
&obj is 0x7ffd9e16b2b0
in ~Obj() 0x7ffd9e16b2b0
與RVO一樣,也可以通過-fno-elide-constructors來禁用NRVO。
NRVO優(yōu)化后,輸出與RVO一致,在下一節(jié),將通過分析實現(xiàn)原理來進行說明。
原理
從上述幾節(jié)中,我們可以看到,編譯器對返回值進行優(yōu)化后,減少了很多不必要的函數(shù)調(diào)用開銷,那么(N)RVO的原理到底是什么呢?
事實上,返回值優(yōu)化的原理是將返回一個類對象的函數(shù)的返回值當(dāng)做該函數(shù)的參數(shù)來處理。
為了能夠更加清晰明了的分析編譯器RVO和NRVO的優(yōu)化機制,我們以下面代碼為例,如下:
Obj fun() {
Obj obj(1);
return obj;
}
int main() {
Obj obj = fun();
return 0;
}
可能會有人有疑問,上面代碼編譯器是可以執(zhí)行NRVO的,為什么還可以RVO呢?這是因為NRVO相比于RVO,是一種要求更為嚴格的優(yōu)化方式,編譯器啟用NRVO的前提條件是返回值是具名的,但并不能說一段代碼可以NRVO就不能RVO。
本節(jié)的內(nèi)容,均是對于<<深度探索C++對象模型>>的理解,如果有誤,請私信或者在評論區(qū)討論
RVO原理
RVO優(yōu)化的原理是消除函數(shù)返回時產(chǎn)生的一次臨時對象。
正如<<深度探索C++對象模型>>中所述,編譯器會將返回值函數(shù)的原型進行調(diào)整,編譯器啟用RVO優(yōu)化,fun()函數(shù)會變成如下:
void fun(Obj &_obj) {
Obj obj(1);
_obj.Obj::Obj(obj); // 拷貝構(gòu)造函數(shù)
return;
}
而main函數(shù)內(nèi)的調(diào)用則會變成:
int main() {
Obj obj; // 僅定義不構(gòu)造
fun(obj);
return 0;
}
經(jīng)過上述轉(zhuǎn)換,編譯器將只調(diào)用一次構(gòu)造函數(shù)和一次拷貝構(gòu)造函數(shù):
- 構(gòu)造函數(shù):fun()函數(shù)中局部對象的構(gòu)造
- 拷貝構(gòu)造函數(shù): 在fun()返回前用局部對象obj的值來拷貝構(gòu)造傳入的引用參數(shù)
經(jīng)過上述優(yōu)化,消除了為保存返回值而創(chuàng)建的臨時對象以及將該局部對象拷貝給該臨時對象的一次拷貝構(gòu)造調(diào)用。
雖然經(jīng)過RVO優(yōu)化后,性能有了部分提升,但是仍然存在一次拷貝構(gòu)造,那么,在哪種場景下,RVO能夠徹底優(yōu)化呢?我們看下如下代碼:
Obj fun() {
return Obj(1);
}
int main() {
Obj obj = fun();
return 0;
}
編譯會將fun函數(shù)優(yōu)化為如下:
void fun(Obj &_obj) {
_obj.Obj::Obj(1);
}
同樣的,main函數(shù)會優(yōu)化為如下:
int main() {
Obj obj;
fun(obj);
return 0;
}
上述兩種代碼都進行了RVO優(yōu)化,但是針對第一段代碼,RVO的優(yōu)化并沒起什么作用,相反第二種代碼塊的優(yōu)化優(yōu)化的更徹底,徹底的消除了拷貝構(gòu)造。
NRVO原理
在上面內(nèi)容中,我們講述了在對一開始的代碼進行了RVO優(yōu)化,但是并沒有徹底優(yōu)化,那么,如果進行NRVO優(yōu)化,編譯器會將上述代碼優(yōu)化成什么樣子呢?
fun函數(shù)會被優(yōu)化成如下:
void fun(Obj &_obj) {
_obj.Obj::Obj(1);
}
同樣的,main函數(shù)會優(yōu)化為如下:
int main() {
Obj obj;
fun(obj);
return 0;
}
fun函數(shù)經(jīng)過優(yōu)化之后,去掉了RVO優(yōu)化遺留的拷貝構(gòu)造問題,達到了優(yōu)化目標(biāo)。
從上述代碼可以看出,同樣一塊代碼,RVO和NRVO的優(yōu)化機制不同,得到的優(yōu)化效果也不同。
編譯器的優(yōu)化,針對不同的場景,采取不同的優(yōu)化方式,了解了這些,方便我們更好地寫出更為高效的代碼。
優(yōu)化失效
在前面幾節(jié)中,我們詳細講解了編譯器在函數(shù)返回值中,啟用(N)RVO進行優(yōu)化,以提升程序性能,但是,編譯器并非智能的,對于某些復(fù)雜場景或者特殊場景,是不會啟用優(yōu)化的,這個時候就需要開發(fā)人員依賴具體的情況,進行具體分析,以達到優(yōu)化的目的。
運行時依賴(根據(jù)不同的條件分支,返回不同變量)
當(dāng)編譯器無法單純通過函數(shù)來決定返回哪個實例對象時,會禁用(N)RVO。
代碼如下:
Obj fun(bool flag) {
Obj o1;
Obj o2;
if (flag) {
return o1;
}
return o2;
}
int main() {
Obj obj = fun(true);
return 0;
}
程序輸出如下:
in Obj() 0x7ffd8cbf7c00 // 構(gòu)造o1對象
in Obj() 0x7ffd8cbf7bf0 // 構(gòu)造o2對象
in Obj(const Obj &obj) 0x7ffd8cbf7c00 0x7ffd8cbf7c30 // 通過拷貝構(gòu)造,將o1賦值給obj(main函數(shù)中的局部變量)
in ~Obj() 0x7ffd8cbf7bf0 // 析構(gòu)o2對象
in ~Obj() 0x7ffd8cbf7c00 // 析構(gòu)o1對象
in ~Obj() 0x7ffd8cbf7c30 // 析構(gòu)obj
但是,下面這種情況例外,雖然其仍然依賴于具體的條件判斷:
Obj fun(bool flag) {
Obj obj;
if (flag) {
return obj;
}
obj.n = 10;
return obj;
}
int main() {
Obj obj = fun(true);
return 0;
}
輸出如下:
in Obj() 0x7ffd8cbf7bf0
in ~Obj() 0x7ffd8cbf7bf0
這是因為,對于單個對象以及多個函數(shù)出口的情況,編譯器將多個出口優(yōu)化為一個。
返回全局變量
當(dāng)返回的對象不是在函數(shù)內(nèi)創(chuàng)建的時候,是無法執(zhí)行返回值優(yōu)化的。
Obj g_obj;
Obj fun() {
return g_obj;
}
int main() {
Obj obj = fun();
std::cout << &obj << std::endl;
return 0;
}
編譯并運行,結(jié)果如下:
in Obj() 0x6013b4 // 構(gòu)造全局變量
in Obj(const Obj &obj) 0x6013b4 0x7ffc8abe14e0 // 構(gòu)造main中的局部對象
0x7ffc8abe14e0
in ~Obj() 0x7ffc8abe14e0 // 析構(gòu)main中的局部對象
in ~Obj() 0x6013b4 // 析構(gòu)全局變量
返回函數(shù)參數(shù)
與返回全局變量類似,當(dāng)返回的對象不是在函數(shù)內(nèi)創(chuàng)建的時候,是無法執(zhí)行返回值優(yōu)化的。
代碼如下:
Obj fun(Obj obj) {
return obj;
}
int main() {
Obj o;
Obj obj = fun(o);
std::cout << "in main " << &obj << std::endl;
return 0;
}
編譯并運行之后,輸出:
in Obj() 0x7ffdbb43da00
in Obj(const Obj &obj) 0x7ffdbb43da00 0x7ffdbb43da10
in Obj(const Obj &obj) 0x7ffdbb43da10 0x7ffdbb43d9f0
in ~Obj() 0x7ffdbb43da10
in main 0x7ffdbb43d9f0
in ~Obj() 0x7ffdbb43d9f0
in ~Obj() 0x7ffdbb43da00
返回成員變量
在某些特殊情況下,即使是未具名變量,也不能RVO。
代碼如下:
struct Wraper {
Obj obj;
};
Obj fun() {
return Wraper().obj;
}
int main() {
Obj obj = fun();
std::cout << &obj << std::endl;
return 0;
}
編譯并運行,結(jié)果如下:
in Obj() 0x7ffed7f85290 // 構(gòu)造Wraper中的obj對象
in Obj(const Obj &obj) 0x7ffed7f85290 0x7ffed7f852c0 // 通過拷貝賦值給main函數(shù)中的局部變量
in ~Obj() 0x7ffed7f85290 // 析構(gòu)Wraper中的obj對象
0x7ffed7f852c0
in ~Obj() 0x7ffed7f852c0 // 析構(gòu)main中的局部對象
存在賦值行為
(N)RVO只能在從返回值創(chuàng)建對象時發(fā)送,在現(xiàn)有對象上使用operator=而不是拷貝/移動構(gòu)造函數(shù),這樣是不會進行RVO操作的。
代碼如下:
Obj fun() {
return Obj();
}
int main() {
Obj obj;
obj = fun();
return 0;
}
編譯并運行之后,輸出:
in Obj() 0x7ffd7a100cf0 // 構(gòu)造main()函數(shù)中的obj對象
in Obj() 0x7ffd7a100d00 // 生成臨時對象
in operator=(const Obj &obj) 0x7ffd7a100d00 0x7ffd7a100cf0 // 調(diào)用賦值函數(shù),將臨時變量賦值給目標(biāo)(main函數(shù)中的局部對象obj)
in ~Obj() 0x7ffd7a100d00 // 析構(gòu)臨時對象
in ~Obj() 0x7ffd7a100cf0 // 析構(gòu)main中的局部對象
使用std::move()返回
在返回值上調(diào)用std::move()進行返回是一種錯誤的方式。它會嘗試強制調(diào)用移動構(gòu)造函數(shù),但這樣會導(dǎo)致RVO失效。因為即使沒有顯示調(diào)用std::move(),編譯器優(yōu)化中也會執(zhí)行move操作。
代碼如下:
Obj fun() {
Obj obj;
return std::move(obj);
}
int main() {
Obj obj = fun();
return 0;
}
輸出如下:
in Obj() 0x7ffe7d4d1720
in Obj(const Obj &&obj)
in ~Obj() 0x7ffe7d4d1720
0x7ffe7d4d1750
in ~Obj() 0x7ffe7d4d1750
從上面輸出可以看出,與不使用std::move()返回相比,使用std::move()返回增加了一次拷貝構(gòu)造調(diào)用和一次析構(gòu)調(diào)用。
經(jīng)驗之談
之前看過一篇文章,也是(N)RVO相關(guān)的,當(dāng)時作者觀點是優(yōu)化依賴于編譯器,而作者同事的觀點則是依賴代碼實現(xiàn)來實現(xiàn)優(yōu)化,當(dāng)時給出的例子如下:
class BigObject {
// 定義
};
BigObject fun() {
BigObject obj;
// do sth
return obj;
}
是不是似曾相識?類似于我們前面NVRO中的代碼示例。
作者的觀點是此種代碼滿足編譯器NVRO優(yōu)化的條件,所以不需要優(yōu)化;而作者同事的觀點則是,不能嚴格依賴編譯器,所以作者同事的優(yōu)化建議如下:
void fun(BigObject &obj) {
// do sth with obj
}
在此,我說下自己的觀點吧:
- 代碼優(yōu)化不應(yīng)該依賴編譯器,因為無法保證在其他編譯器下就能得出跟當(dāng)前類似的優(yōu)化效果
- 依賴編譯器優(yōu)化的前提是開發(fā)人員了解編譯器的優(yōu)化機制或者說開發(fā)人員知道寫怎樣的代碼能達到編譯器優(yōu)化的標(biāo)準(zhǔn),但是,如果部門入職的新人接手了這塊工作,在開發(fā)過程中,發(fā)現(xiàn)老代碼都是直接返回(也就是作者口中的編譯器優(yōu)化),然后新人也直接返回(即使編譯器不會進行優(yōu)化,例如前面的返回全局變量等),這樣恰恰得到相反的結(jié)果
所以,總的來說,我傾向于作者同事的優(yōu)化方案。對于char、int、double等元類型,在函數(shù)中直接返回;而對于需要返回struct、class類型的函數(shù),則直接作為函數(shù)入?yún)?,在函?shù)內(nèi)部進行初始化。
當(dāng)然了,上面僅僅是我的個人觀點,至于使用編譯器優(yōu)化還是上述引用傳參的方式,則依賴于開發(fā)者的個人喜好或者團隊的代碼風(fēng)格。但是需要注意的是,如果使用編譯器優(yōu)化,則需要小心小心再小心,否則就會導(dǎo)致事倍功半的效果,進而導(dǎo)致程序性能損失。
結(jié)語
(N)RVO是編譯器對于函數(shù)返回值的一種優(yōu)化技術(shù),旨在消除臨時對象的創(chuàng)建。了解編譯器的優(yōu)化,可以提升我們的程序運行效率,但是需要注意的是,如果單純依賴編譯器優(yōu)化,可能會導(dǎo)致某些我們意想不到的情況發(fā)生。所以,在使用編譯器優(yōu)化方式之前,我們需要保證代碼的實現(xiàn)方式能夠啟用RVO優(yōu)化。
好了,今天的文章就到這里,我們下期見!
網(wǎng)站名稱:編譯器之返回值優(yōu)化
文章轉(zhuǎn)載:http://fisionsoft.com.cn/article/dhogije.html


咨詢
建站咨詢
