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

相关问题