深度探索C++物件模型之(九)

來源:互聯網
上載者:User

=====================================================================

如果喜歡,請關註:JellyThink | 思想的果凍

更多原創精彩博文,盡在www.jellythink.com

還可以關注新浪微博:http://weibo.com/u/1887014677

=====================================================================

Named Return Value(實際上就是傳回值最佳化)
當一個函數返回一個對象的執行個體,一個臨時對象被建立並通過拷貝建構函式傳回其值。但是在C++標準中,允許省略拷貝建構函式的對象(前提是所有的路徑返回相同的對象),這個也是每個C++編譯器義不容辭的責任。
有如下的代碼:

#includeusing namespace std; class TestA{public :     TestA(){cout<< "Constructor" <<endl;}     ~TestA(){cout<< "Destructor" <<endl;}      TestA( const TestA& test)     {          cout<< "Copy Constructor" <<endl;     } }; TestA GetTest() {      TestA test;      return test; } int main() {      TestA testA;       testA = GetTest();      return 0 ; }

函數GetTest獲得一個類的對象,在編譯器內部,對於函數GetTest的實際處理會是怎麼樣的?我先前的部落格中有寫到,調用和不調用Copy Constructor的時機,而現在的GetTest函數現在就是需要調用Copy Constructor的一種情況。輸出如下:

Constructor Constructor Copy Constructor Destructor Destructor Destructor 請按任意鍵繼續. . .

在實際運行上述代碼的時候,會輸出Copy Constructor,是的,調用了Copy Constructor。這樣正好符合我之前的博文中所說的那樣。函數GetTest對於編譯器來說,會被擴充的,如下:

void GetTest(TestA &result) {      TestA test;      test.TestA::TestA(); //constructor      // Do something with test object      // ...            result.TestA::TestA(test);      return ; } 

就像上述函數GetTest函數被編譯器展開後的樣子,所有的路徑都返回相同的Named Value,因此編譯器可以做自己的最佳化。直接以result取代Named Return Valued. 是的,編譯器是要進行最佳化的。預設的情況下,visual studio 2010是關閉NRV的,我們可以在項目屬性->配置屬性->C/C++->最佳化中是選擇禁用的,所有沒有進行最佳化,你可以開啟這個開關(/o2),然後編譯上述程式,Copy Constructor是不會調用的。這就是編譯器的最佳化,程式輸出如下:

ConstructorConstructorDestructorDestructor請按任意鍵繼續. . .

可以看到,實際少的一次Constructor和一次Destructor正好說明在GetTest函數中的那個產生的result少了,沒有了對result的產生和析構。現在是有Copy Constructor而被最佳化掉了,沒有被調用,如果沒有Copy Consturctor呢?我把上面的Copy Consturctor注釋掉。運行結果如下:

ConstructorConstructorDestructorDestructorDestructor請按任意鍵繼續. . .

使用MinGW進行編譯結果如下(即使有了Copy Consturctor也是一樣):

ConstructorConstructorDestructorDestructor請按任意鍵繼續. . .

你會感到很驚訝,怎麼會不一樣呢?
在《深度探索C++物件模型》一書中有說,Copy Constructor的出現啟用了C++編譯器中的NRV最佳化,NRV最佳化並不通過其它的獨立的最佳化工具完成。可見,這樣得到的結果和書中所述是有出路的。事實上,即使是沒有定義拷貝建構函式和解構函式,而是由編譯器產生(在需要時),NRV依然會對程式的效率產生影響。而Visual Studio 2010中少的那次Constructor調用就是預設拷貝建構函式的調用。
在進行大量對象的複製時,NRV能最佳化程式,提高效率;但是對於NRV帶來的副作用,你可以這麼想,就比如在Visual Studio 2010中,剛剛那次隱晦的調用Copy Constructor你知道它的調用嗎?也就是說編譯器覺的合適,就會產生一個預設的建構函式,但是什麼是合適的,我現在不知道,我覺得我也應該不知道,就是因為這種不知道,才給我們日後的編程中埋下了隱患。比如:你的類中有一個static變數記錄這個對象被拷貝的次數,由於這種隱患,就很可能給程式產生的結果與預期的不一致;同時,因為NRV,建構函式也不會得到調用,而有的時候,我們期望有些在Copy Constructor中的語句能得到調用,但是如果有了NRV,那就不可能了。
所以,最後,需不需要NRV,視你的具體情況而定。

2013/2/4 於東軟-大連

=====================================================================

如果喜歡,請關註:JellyThink | 思想的果凍

更多原創精彩博文,盡在www.jellythink.com

還可以關注新浪微博:http://weibo.com/u/1887014677

=====================================================================

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.