2

我知道,對於非POD類型的默認初始化也將默認通過調用其默認構造函數初始化非靜態非POD成員變量。但我不確定這是怎麼發生的。這裏是我的意思的例子:困惑用戶如何空定義的構造函數將初始化非靜態非POD的成員變量

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

class Test2 { 
    public: 
    Test2() {cout <<"Here";} 
}; 

class Test { 
    public: 
    Test() {} 
    Test2 i; 
}; 

int main() { 
    Test foo; 
} 

輸出是:

Here 

基於C++的初始化標準(8.5),默認初始化:

— if T is a non-POD class type (clause 9), the default constructor 
for T is called (and the initialization is ill-formed if T has no 
accessible default constructor); 

所以鑑於此,我確實希望默認構造函數Test()會被調用,但是類Test的空默認構造函數不會初始化Test2 i expli毋庸置疑,Test2()不知何故被暗中調用。我想知道的是這是怎麼發生的?同樣,對於值初始化(與上面的例子沒有關係),如果一個空的用戶定義的默認構造函數沒有顯式地初始化一個POD非靜態成員變量,那麼這個變量如何得到零初始化(我知道它是這樣做的做)?由於基於標準,似乎對於值初始化來說,當你有一個用戶定義的默認構造函數時發生的一切就是構造函數被調用。

的值初始化C++標準的相應部分如下:

— if T is a class type (clause 9) with a user-declared constructor (12.1), then the 
default constructor for T is called (and the initialization is ill-formed if T has no 
accessible default constructor); 

這個問題類似於c++ empty constructor and member initialization 但不同的是,而不是問最終結果的行爲是什麼,我會想知道爲什麼會發生最終結果行爲。

+0

編譯器寫入遵循的標準奠定了規則,標準說,X應該發生在情況Y中,所以編譯器發出代碼來在情況Y中執行X.我不明白這是如何造成混淆的。 –

+0

如果你沒有在構造函數中初始化它的初始化爲ou –

+0

@Benjamin:我的困惑是,我認爲X應該發生在情況Y有副作用,其中副作用不被我上面列出的標準解釋。 – user1082160

回答

2

在C++ 11標準,12.6節第8段:

在非委託構造,如果一個給定的非靜態數據成員或基類不被指定一個MEM-initializer- ID(包括其中不存在MEM-初始化列表的情況下,因爲構造函數沒有構造函數初始化程序)和實體不是虛擬基類的抽象類(10.4),那麼

  • 如果實體是一個非靜態數據成員,它有一個括號或等於初始值設定項,該實體被初始化爲 8.5;否則,如果實體是變體成員(9.5),則不執行初始化;否則,不執行初始化;否則,如果實體是變體成員(9.5),則不執行初始化;否則,不執行初始化。
  • 否則,實體將被默認初始化(8.5)。

您所遇到的第三種情況,在沒有初始化的成員,該成員是不是一個變體成員,所以在這種情況下,它是默認初始化。

另外,從第10段:

在非委託構造,初始化進行以下順序: - 首先,只對最派生類(1的構造。8)中,虛擬基類以它們出現在基類的有向無環圖的深度優先從左到右的遍歷中的順序進行初始化,其中「從左到右」是基類的出現順序在派生類base-specifier-list中。

  • 然後,直接基類中聲明的順序,因爲它們出現在基本說明符列表 (不管MEM-初始化的順序的)進行初始化。
  • 然後,按照靜態數據成員在類定義 (同樣不考慮mem初始化器的順序)中聲明的順序對其進行初始化。
  • 最後,執行構造函數體的複合語句。

無論你在構造函數中指定什麼,成員會執行構造函數體之前被初始化。

的MEM-初始化-id爲用於指代一個部件在構造函數初始化列表標識符:

class Test { 
    public: 
    Test() : i() {} // Here `i` is a mem-initializer-id 
    Test2 i; 
}; 
+0

啊我看到了,我不知道這部分的標準。只是好奇,mem-initializer-id是什麼? – user1082160

+1

@ user1082160:我在我的答案中添加了一些解釋。 –

+0

最後一個問題,我從標準u發佈(12.6第8段)中注意到,它沒有真正提到如何進行值初始化,即使用戶定義的空默認構造函數沒有初始化pod,非靜態pod類型也會初始化爲零類型。從標準來看,我認爲pod類型會得到默認初始化,這意味着它沒有被初始化。 – user1082160

0

根據C++標準的草案http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf發現,部分12.6.2:

如果給定的非靜態數據成員或基類未由mem-initializer-id命名(包括由於構造函數沒有ctor-initializer而沒有mem-initializer-list的情況),那麼

- 如果實體是(可能是cv合格的)類類型(或其數組)或基類的非靜態數據成員,且實體類是非POD類,則該實體是默認初始化的8.5)。如果實體是一個const限定類型的非靜態數據成員,則實體類應該有一個用戶聲明的默認構造函數。

- 否則,實體未初始化。如果實體屬於常量限定類型或引用類型,或者包含(直接或間接)常量限定類型成員的(可能爲符合cv要求的)POD類類型(或其數組),則該程序不適用,形成。

換句話說,如果一個非POD類類型的對象並不在初始化列表顯示,編譯器將其解釋爲如果對象似乎與它的默認構造函數被調用。

另外,請注意其他類型(即基元和POD類型)未初始化,這與您在問題中指出的不同。全局對象是零初始化的,但堆棧中的對象也是如此。這裏是一個小程序我放在一起以測試:

#include <iostream> 

class T 
{ 
public: 
    T() {} 

    void put(std::ostream &out) 
    { 
     out << "a = " << a << std::endl; 
     out << "b = " << b << std::endl; 
     out << "c = " << c << std::endl; 
    } 
private: 
    int a; 
    int b; 
    int c; 
}; 

T t2; 

int main() 
{ 
    T t; 
    t.put(std::cout); 
    t2.put(std::cout); 

    return 0; 
} 

使用g ++ 4.5.2編譯,我得到以下輸出:

與用戶定義的默認的類型的
a = 8601256 
b = 3 
c = 2130567168 
a = 0 
b = 0 
c = 0 
+0

我提到的值初始化做零初始化pod類型,而不是默認的初始化。這裏你是默認初始化T,這就是爲什麼沒有初始化pod類型的原因。 – user1082160

相關問題