2014-01-18 44 views
2

我想了解更多關於C++的知識,我對編譯器的工作感到困惑。我寫了下面的文件,詳細的意見發生了什麼:C++中的構造11

Test getTest() 
{ 
    return Test(100, string("testing...")); 
} 

int main() 
{ 
    // These two will call the initializer constructor... 
    Test t1(5, string("hello")); 
    Test t2(10, string("goodbye")); 

    // This will not call operator=. This will call the copy constructor! 
    Test t3 = t1; 

    // This will call operator=(Test&) 
    t3 = t2; 

    // This will call operator=(Test&&) because rhs is an rvalue 
    // We will swap the resources in this operator= so that when getTest() 
    // deletes its resources, it will actually be deleting t3's old resources. 
    // Likewise, t3 will get getTest()'s resources. 
    t3 = getTest(); 


    // I don't know what this is doing, but I know it's not calling the destructor. 
    // I beleive that the memory of t4 is simply what was returned by getTest(). 
    // Likewise with t5. 
    Test t4(getTest()); 
    Test* t5 = new Test(getTest()); 

    Test t6(t4); 

    return 0; 
} 

看來,T4和T5沒有進入任何構造函數,事實上只是用()由getTest分配的內存。我認爲會發生的是t4會進入rValue拷貝構造函數:測試(const測試& & rhs),但它甚至沒有它的參數是一個rValue。測試t4(getTest())不調用任何析構函數,這就是爲什麼我認爲t4只是獲取內存。 t6會調用複製構造函數。

我看着在Visual Studio 2013的彙編代碼,發現如下:

Test t4(getTest()); 
00F59B8C push  8 
00F59B8E lea   ecx,[t4] 
00F59B91 call  Test::__autoclassinit2 (0F51285h) 
00F59B96 lea   eax,[t4] 
00F59B99 push  eax 
00F59B9A call  getTest (0F51456h) 
00F59B9F add   esp,4 
00F59BA2 mov   byte ptr [ebp-4],8 

因此,它看起來像它被稱爲autoclassinit2調用的東西,然後讓從getTest內存,並最終將其存儲在T4 ?

所以我想我的問題是:這只是一個編譯器優化,直接從getTest()構造函數給內存到t4?而不是說,1.在getTest()中構造2.調用rVal拷貝構造函數3.銷燬getTest()內存?還是有其他事情在這裏?謝謝!

+0

看看[*返回值優化*](http://en.wikipedia.org/wiki/Return_value_optimization)。 – juanchopanza

+0

哦,我明白了,所以這是一個編譯器優化。它通過做一些相同的東西來繞過拷貝構造器,除了不需要調用析構函數。很酷,但很奇怪,因爲我在調試時看不到它!我只是想確保這裏沒有魚腥味,就像它調用了一些我沒有想到的默認和效率較低的構造函數。非常感謝這個鏈接。這基本上回答了我的問題 – user2045279

+0

請注意,這不是普通的編譯器優化:它不是「相同的」。允許RVO(和一般的複製elision)改變程序的行爲。 – juanchopanza

回答

3

=在一個聲明中意味着'隱式構造請求'(基本上)而不是'調用操作符='。

C++有一個被稱爲elision的概念。 Elision意味着'使兩個或更多變量成爲同一個事物'。有關於編譯器何時可以執行的規則。與其他優化不同,即使存在副作用也是合法的。

如果使用相同類型的未命名臨時變量初始化變量,編譯器可以暫時取消該臨時變量。如果你從一個函數返回一個局部變量,它可以(在某些情況下)被忽略爲未命名的返回值。同上,用於臨時匿名回報。 NRVO和RVO是您想要的關鍵字。

在很多情況下,如果elision由於技術原因或編譯器限制而失敗,則隱式發生move。但明確的move塊elision。因此瞭解這些規則對於出血邊緣優化代碼很重要。

+0

這進一步討論了juanchopanza正在談論的內容。我很欣賞這個答覆,非常感謝 – user2045279