您好,登錄后才能下訂單哦!
命名的返回值優(yōu)化(NRVO),這優(yōu)化了冗余拷貝構(gòu)造函數(shù)和析構(gòu)函數(shù)調(diào)用,從而提高了總體性能。值得注意的是,這可能導(dǎo)致優(yōu)化和非優(yōu)化程序之間的不同行為。
下面是代碼段1中的一個(gè)簡(jiǎn)單示例,以說(shuō)明優(yōu)化及其實(shí)現(xiàn)方式:
A MyMethod (B &var)
{
A retVal;
retVal.member = var.value + bar(var);
return retVal;
}
使用上述函數(shù)的程序可能具有如下構(gòu)造:
valA = MyMethod(valB);
從MyMethod返回的值是在valA通過使用隱藏的參數(shù)所指向的內(nèi)存空間中創(chuàng)建的。下面是當(dāng)我們公開隱藏的參數(shù)并顯示地顯示構(gòu)造函數(shù)和析構(gòu)函數(shù)時(shí)的功能:
A MyMethod(A &_hiddenArg, B &var)
{
A retVal;
retVal.A::A(); //constructor for retVal
retVal.member = var.value + var(var);
_hiddenArg.A::A(retVal); // the copy constructor for A
return;
return.A::~A(); // destructor for retVal
}
上段代碼為不使用NRVO的隱藏參數(shù)代碼(偽代碼)
從上面的代碼可以看出,有一些優(yōu)化的機(jī)會(huì)。其基本思想是消除基于堆棧的臨時(shí)值(retVal)并使用隱藏的參數(shù)。因此,這將消除基于堆棧的值的拷貝構(gòu)造函數(shù)和析構(gòu)函數(shù)。下面是基于NRVO的優(yōu)化代碼:
A MyMethod(A &_hiddenArg, B &var)
{
_hiddenArg.A::A();
_hiddenArg.member = var.value + bar(var);
Resurn
}
帶有NRVO的隱藏參數(shù)代碼(偽代碼)
代碼示例
示例1:簡(jiǎn)單示例
#include <stdio.h>
class RVO
{
public:
RVO() { printf("I am in constructor\n"); }
RVO( const RVO& c_RVO ) { printf("I am in copy constructor\n"); }
~RVO() { printf("I am in destructor\n"); }
int mem_var;
};
RVO MyMethod(int i)
{
RVO rvo;
rvo.mem_var = i;
return rvo;
}
int main()
{
RVO rvo;
rvo = MyMethod(5);
}
代碼:Sample1.cpp
如果沒有NRVO,預(yù)期的輸出將是:
I am in constructor
I am in constructor
I am in copy constructor
I am in destructor
I am in destructor
I am in destructor
使用NRVO,預(yù)期的輸出將是:
I am in constructor
I am in constructor
I am in destructor
I am in destructor
示例2:更復(fù)雜的示例
#include <stdio.h>
class A
{
public:
A()
{
printf("A: I am in constructor\n");
i = 1;
}
~A()
{
printf("A: I am in destructor\n");
i = 0;
}
A(const A& a)
{
printf("A: I am in copy constructor\n");
i = a.i;
}
int i, x, w;
};
class B
{
public:
A a;
B()
{
printf("B: I am in constructor\n");
}
~B()
{
printf("B: I am in destructor\n");
}
B(const B& b)
{
printf("B: I am in copy constructor\n");
}
};
A MyMethod()
{
B* b = new B();
A a = b->a;
delete b;
return a;
}
int main()
{
A a;
a = MyMethod();
}
代碼Sample2.cpp
無(wú)NRVO的輸出將如下所:
A: I am in constructor
A: I am in constructor
B: I am in constructor
A: I am in copy constructor
B: I am in destructor
A: I am in destructor
A: I am in copy constructor
A: I am in destructor
A: I am in destructor
A: I am in destructor
當(dāng)NRVO優(yōu)化啟動(dòng)時(shí),輸出將是:
A: I am in constructor
A: I am in constructor
B: I am in constructor
A: I am in copy constructor
B: I am in destructor
A: I am in destructor
A: I am in destructor
A: I am in destructor
優(yōu)化限制
有些情況下,優(yōu)化不會(huì)真正啟動(dòng)。以下是這些限制的樣本
示例3:異常示例
在遇到異常時(shí),隱藏的參數(shù)必須在它正在替換的臨時(shí)范圍內(nèi)被破壞。
// RVO class is defined above in figure 4
#include <stdio.h>
RVO MyMethod(int i)
{
RVO rvo;
cvo.mem_var = i;
throw "I am throwing an exception!";
return rvo;
}
int main()
{
RVO rvo;
try
{
rvo = MyMethod(5);
}
catch(char* str)
{
printf("I caught the exception\n");
}
代碼Sample3.cpp
如果沒有NRVO,預(yù)期的輸出將是:
I am in constructor
I am in constructor
I am in destructor
I caught the exception
I am in destructor
如果“拋出”被注釋掉,輸出將是:
I am in constructor
I am in constructor
I am in copy constructor
I am in destructor
I am in destructor
I am in destructor
現(xiàn)在,如果“拋出”被注釋掉,并且NRVO被觸發(fā),輸出將如下所示:
I am in constructor
I am in constructor
I am in destructor
I am in destructor
也就是說(shuō)sample3.cpp在沒有NRVO的情況下,會(huì)表現(xiàn)出相同的行為。
示例4:不同的命名對(duì)象示例
若要使用優(yōu)化,所有退出路徑必須返回同一命名對(duì)象。
#include <stdio.h>
class RVO
{
public:
RVO()
{
printf("I am in construct\n");
}
RVO(const RVO& c_RVO)
{
printf("I am in copy construct\n");
}
int mem_var;
};
RVO MyMethod(int i)
{
RVO rvo;
rvo.mem_var = i;
if( rvo.mem_var == 10 )
return RVO();
return rvo;
}
int main()
{
RVO rvo;
rvo = MyMethod(5);
}
代碼Sample4.cpp
啟用優(yōu)化時(shí)輸出與不啟用任何優(yōu)化相同。NRVO實(shí)際上并不發(fā)生,因?yàn)椴⒎撬蟹祷囟挤祷叵嗤膶?duì)象。
I am in constructor
I am in constructor
I am in copy constructor
如果將上面的示例更改為返回rvo。在返回對(duì)象時(shí),優(yōu)化將消除復(fù)制構(gòu)造函數(shù):
#include <stdio.h>
class RVO
{
public:
RVO()
{
printf("I am in constructor\n");
}
RVO(const RVO& c_RVO)
{
printf("I am in copy constructor\n");
}
int mem_var;
};
RVO MyMethod(int i)
{
RVO rvo;
if( i == 10 )
return rvo;
rvo.mem_var = i;
return rvo;
}
int main()
{
RVO rvo;
rvo = MyMethod(5);
}
代碼Sample4_Modified.cpp修改并使用NRVO,輸出結(jié)果將如下所示:
I am in constructor
I am in constructor
優(yōu)化副作用
程序員應(yīng)該意識(shí)到這種優(yōu)化可能會(huì)影響應(yīng)用程序的流程。下面的示例說(shuō)明了這種副作用:
#include <stdio.h>
int NumConsCalls = 0;
int NumCpyConsCalls = 0;
class RVO
{
public:
RVO()
{
NumConsCalls ++;
}
RVO(const RVO& c_RVO)
{
NumCpyConsCalls++;
}
};
RVO MyMethod()
{
RVO rvo;
return rvo;
}
int main()
{
RVO rvo;
rvo = MyMethod();
int Division = NumConsCalls / NumCpyConsCalls;
printf("Construct calls / Copy constructor calls = %d\n", Division);
}
代碼段Sample5.cpp
編譯未啟用優(yōu)化將產(chǎn)生大多數(shù)用戶所期望的?!皹?gòu)造函數(shù)”被調(diào)用兩次?!翱截悩?gòu)造函數(shù)”被調(diào)用一次。因此除法生成2。
Constructor calls / Copy constructor calls = 2
另一方面,如果上面的代碼通過啟用優(yōu)化進(jìn)行編譯,NRVO將會(huì)啟用。因此“拷貝構(gòu)造函數(shù)”調(diào)用將被刪除。因此,NumCpyConsCalls將為零,導(dǎo)致異常。如果沒有適當(dāng)處理,可以導(dǎo)致應(yīng)用程序崩潰。
引入自:https://msdn.microsoft.com/en-us/library/ms364057(v=vs.80).aspx
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。