2009-02-25 99 views
12

簡單的問題:下列語句是否等價?或者是第二個在幕後做更隱含的事情(如果是這樣,是什麼?)C++構造函數的語法

myClass x(3); 
myClass x = myClass(3); 

謝謝!

回答

25

它們不完全相同。第一個被稱爲「直接初始化」,而第二個被稱爲「複製初始化」。

現在,標準制定了兩條規則。第一種是直接初始化和複製初始化,其中初始化器是初始化對象的類型。第二個規則是在其他情況下進行復制初始化。

因此,從這個角度來看,兩者都被稱爲一個 - 第一個規則。在使用相同類型進行復制初始化的情況下,允許編譯器刪除副本,以便它可以將您創建的臨時構造直接構建到初始化對象中。所以你最終可以用相同的代碼生成。但是拷貝構造函數,即使拷貝被刪除(優化出來),仍然可用。也就是說,如果你有一個私人拷貝構造函數,那麼如果它出現的代碼無法訪問它,代碼就是無效的。

第二種稱爲拷貝初始化,因爲如果初始化的類型是不同類型的,在試圖右側隱式轉換到左側創建的臨時對象:

myclass c = 3; 

編譯器創建一個myclass類型的臨時對象,然後當有構造函數接受一個int時。然後它用那個臨時對象初始化對象。同樣在這種情況下,可以在初始化對象中直接創建臨時創建的對象。您可以按照以下步驟在您的課程的構造函數/析構函數中打印消息,並使用用於GCC的選項-fno-elide-constructors。它不會嘗試去複製副本。

在附註上,上面的代碼與賦值運算符無關。在這兩種情況下,發生的都是初始化。

+0

「myclass c = 3」似乎只是直接調用「myclass(int x)」,而不是使用臨時的myclass對象。 – 2009-02-25 20:07:15

8

如果您的編譯器未實現複製elision,則第二個可能會或可能不會要求額外的myclass對象構造。但是,大多數構造函數,即使沒有任何優化開關,也會默認打開副本。

注意初始化,而建設永遠不會調用賦值運算符。

始終,請記住:

assignment: an already present object gets a new value

initialization: a new object gets a value at the moment it is born.

+0

這與NRVO無關。 – 2009-02-25 18:12:42

+0

我的意思是這個elision,當時不能拿出正確的名詞。謝謝。使用VC9的 – dirkgently 2009-02-25 18:14:19

5

在第二個,臨時對象被首先創建,然後複製到對象x使用myClass的的拷貝構造函數。因此兩者都不相同。

4

我寫了下面的嘗試和 說明 明白這是怎麼回事:

#include <iostream> 

using namespace std; 

class myClass 
{ 
public: 
    myClass(int x) 
    { 
     this -> x = x; 
     cout << "int constructor called with value x = " << x << endl; 
    } 

    myClass(const myClass& mc) 
    { 
     cout << "copy constructor called with value = " << mc.x << endl; 
     x = mc.x; 
    } 

    myClass & operator = (const myClass & that) 
    { 
     cout << "assignment called" << endl; 
     if(this != &that) 
     { 
      x = that.x; 
     } 
     return *this; 
    } 

private: 
    int x; 
}; 

int main() 
{ 
    myClass x(3); 
    myClass y = myClass(3); 
} 

當我編譯和運行這個代碼,我得到以下輸出:

$ ./a.out 
int constructor called with value x = 3 
int constructor called with value x = 3 

似乎表示在主函數中進行的兩次調用沒有區別,但這是錯誤的。正如litb指出的那樣,複製構造函數必須可用於此代碼的工作,即使它在這種情況下被取消。爲了證明這一點,只需將上面代碼中的複製構造函數移動到類定義的專用部分即可。您應該看到以下錯誤:

$ g++ myClass.cpp 
myClass.cpp: In function ‘int main()’: 
myClass.cpp:27: error: ‘myClass::myClass(const myClass&)’ is private 
myClass.cpp:37: error: within this context 

還要注意的是賦值運算符是從未調用。