溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C++ 命名返回值優(yōu)化(NRVO)

發(fā)布時(shí)間:2020-06-14 18:17:17 來(lái)源:網(wǎng)絡(luò) 閱讀:1775 作者:XDATAPLUS 欄目:編程語(yǔ)言

命名的返回值優(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

向AI問一下細(xì)節(jié)

免責(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)容。

AI