[C++] NRV優化

昨天,室友發給我一個程序讓我運行,代碼如下:

#include <iostream>
#include <string>
using namespace std;

class Trans 
{
public:
	Trans() : a(12) {};
	Trans(int id) : a(0), i(id) {};
	~Trans() {
		cout << "good bye " << i << endl;
	}
	friend std::ostream& operator<<(ostream&, const Trans&);
	friend Trans operator + (const Trans&, const Trans&);
private:
	int a;
	int i;
};

std::ostream& operator<<(ostream& os, const Trans& tra)
{
	return os << tra.a << endl;
}

Trans operator + (const Trans& t1, const Trans& t2)
{
	Trans t(3);
	t.a = t1.a + t2.a;
	return t;
}

int main()
{
	Trans p(1), q(2);
	cout << p + q;
	return 0;

}

我的運行結果是這樣的:


然後將執行結果截圖給室友看,室友說跟它的執行結果不一樣,他的執行結果在0的前面多了一個good bye 3。這裏就不給截圖了。

首先說明,我用的GCC,室友用的是VS。同樣的程序在不同的編譯器下的執行結果不一樣,那麼,只有一種解釋:編譯器在幕後給你幹了一些事情。

我想到了《深度探索C++對象模型》中的NRV(Named Return Value)優化。

對於函數:

Trans operator + (const Trans& t1, const Trans& t2)
{
	Trans t(3);
	t.a = t1.a + t2.a;
	return t;
}

編譯器會將它轉換爲類似這樣:

void operator +(Trans *this, const Trans& t1, const Trans& t2, Trans &__result)
{
    Trans t(3);
	t.a = t1.a + t2.a;
	__result(t);
	return;
}

以上的代碼在變量和函數名上並沒有像編譯器一樣進行轉換,這裏只關注編譯器是如何返回對象的。

如果編譯器採用NVR優化,代碼就會被轉換成類似這樣:

void operator +(Trans *this, const Trans& t1, const Trans& t2, Trans &__result)
{
    __result.Trans::Trans(3);
	__result.a = t1.a + t2.a;
	return;
}

因此,如果不採用NVR優化,在返回一個對象時,會再創建一個臨時對象用於獲取返回值,因此,此函數會產生兩個對象,如果採用NVR優化,在返回一個對象時,直接用返回值去取代函數內部的局部對象,此時,函數只產生一個對象。所以,對於VS和GCC的不同,或許(這只是我的一種解釋這種行爲的想法)可以理解爲VS沒有采用NVR優化,所以會有兩個對象析構,而GCC採用了NVR優化,所以只有一個對象被析構。


參考資料:

深度探索C++對象模型,66頁,在編譯器層面做優化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章