默认构造函数是不是初始化内置类型?

Posted

技术标签:

【中文标题】默认构造函数是不是初始化内置类型?【英文标题】:Does the default constructor initialize built-in types?默认构造函数是否初始化内置类型? 【发布时间】:2011-01-25 21:37:19 【问题描述】:

默认构造函数(由编译器创建)是否初始化内置类型?

【问题讨论】:

【参考方案1】:

隐式定义(由编译器)类的默认构造函数不会初始化内置类型的成员。

但是,您必须记住,在某些情况下,可以通过其他方式执行类实例的初始化。不是默认构造函数,也不是构造函数。

例如,人们普遍认为C 类的语法C() 总是调用默认构造函数。但实际上,语法C() 执行类实例的所谓值初始化。如果它是用户声明的,它只会调用默认构造函数。 (那是在 C++03 中。在 C++98 中 - 仅当类是非 POD 时)。如果该类没有用户声明的构造函数,那么C() 将不会调用编译器提供的默认构造函数,而是会执行一种完全不涉及C 构造函数的特殊类型的初始化。相反,它将直接对类的每个成员进行值初始化。对于内置类型,它会导致零初始化。

例如,如果你的类没有用户声明的构造函数

class C  
public:
  int x;
;

然后编译器将隐式提供一个。编译器提供的构造函数什么都不做,这意味着它不会初始化C::x

C c; // Compiler-provided default constructor is used
// Here `c.x` contains garbage

尽管如此,以下初始化零初始化 x,因为它们使用显式 () 初始化器

C c = C(); // Does not use default constructor for `C()` part
           // Uses value-initialization feature instead
assert(c.x == 0);

C *pc = new C(); // Does not use default constructor for `C()` part
                 // Uses value-initialization feature instead
assert(pc->x == 0);

() 初始化程序的行为在 C++98 和 C++03 之间的某些方面有所不同,但在这种情况下则不同。对于上面的类C,它将是相同的:() 初始化程序执行C::x 的零初始化。

另一个不涉及构造函数的初始化示例当然是聚合初始化

C c = ; // Does not use any `C` constructors at all. Same as C c; in C++11.
assert(c.x == 0);

C d; // C++11 style aggregate initialization.
assert(d.x == 0);

【讨论】:

注意!根据***.com/a/3931589/18775,Visual Studio C++ 编译器和 C c = C(); 中有一个错误。可能并不总是有效。 在 C++11 中:C c 会用0 初始化x 吗? 如果您使用C() = default;,这将如何工作?这仍然会为new C(); 执行值初始化和为new C; 执行默认初始化吗? @MarkIngram 有点晚了,但是是的:如果您使用C() = default;,您将获得new C(); 的值初始化和new C; 的默认初始化。参考:***.com/a/42049188/746890 这个答案很好,但它只讨论了C 是 POD 的情况。如果这个答案能提到当情况不平凡或非标准布局时情况如何变化,那就太好了。【参考方案2】:

我不太确定你的意思,但是:

struct A  int x; ;

int a; // a is initialized to 0
A b;   // b.x is initialized to 0

int main() 
    int c;         // c is not initialized
    int d = int(); // d is initialized to 0

    A e;           // e.x is not initialized
    A f = A();     // f.x is initialized to 0

在我说“未初始化”的每种情况下 - 你可能会发现你的编译器给它一个一致的值,但标准并不要求它。

很多人都在挥手,包括我在内,关于“有效”的内置类型如何具有默认构造函数。实际上默认初始化和值初始化是标准中定义的术语,我个人每次都必须查找。只有类在标准中定义为具有隐式默认构造函数。

【讨论】:

【参考方案3】:

出于所有实际目的 - 不。


但是对于在技术上符合 C++ 标准的实现,答案是它取决于对象是否为 POD 以及如何初始化它。 根据 C++ 标准:

MyNonPodClass instance1;//built in members will not be initialized
MyPodClass instance2;//built in members will be not be initialized
MyPodClass* instance3 = new MyPodClass;//built in members will not be initialized
MyPodClass* instance3 = new MyPodClass() ;//built in members will be zero initialized

但是,在现实世界中,这并没有得到很好的支持,所以不要使用它。


标准的相关部分是第 8.5.5 和 8.5.7 节

【讨论】:

全局变量呢,它们不总是零初始化吗? 除了第一个之外,没有调用默认构造函数。事实上,它们的默认 ctor 做同样的事情(它们不初始化任何东西)——毕竟它们都是同一个类。第四,编译器只是value初始化POD,不调用默认构造函数。 @FredOverflow,所有命名空间范围和本地或类静态对象都被零初始化,与它们的类型无关(它们可能是最复杂的类——它们仍然会被零初始化)。 “内置成员不会被初始化”是什么意思?【参考方案4】:

根据标准,除非您在初始化列表中显式初始化,否则不会这样做

【讨论】:

好吧,你不能在默认构造函数中指定任何东西由编译器创建 @Gorpik -- 点...但是我说显式初始化,我的意思是必须显式提供默认构造函数 @hype:我知道,但 OP 指出他说的是计算机创建的默认构造函数,而不是你自己提供的构造函数。【参考方案5】:

正如前面的发言者所说 - 不,它们没有被初始化。

这实际上是真正奇怪错误的来源,因为现代操作系统倾向于用零填充新分配的内存区域。如果您期望这样做,它可能会第一次起作用。但是,随着您的应用程序继续运行,delete-ing 和 new-ing 对象,您迟早会遇到这样的情况:您期望零,但早期对象的非零剩余存在。

那么,为什么不是所有new-ed 数据都是新分配的?是的,但并不总是来自操作系统。操作系统倾向于使用更大的内存块(例如,一次 4MB),因此所有微小的“这里一字三字节那里”的分配和释放都在 uyserspace 中处理,因此不会清零。

PS。我写了“tend to”,也就是说,你甚至不能依赖第一次成功...

【讨论】:

【参考方案6】:

从技术上讲,它确实会初始化它们——通过使用它们的默认构造函数,顺便说一句,它只是为它们分配内存。

如果您想知道它们是否被设置为像 ints 的 0 之类的正常值,那么答案是“否”。

【讨论】:

构造函数没有分配内存。构造函数在内存分配后执行。如果我错了,请纠正我。【参考方案7】:

没有。默认构造函数分配内存并调用任何父级的无参数构造函数。

【讨论】:

以及任何非 POD 成员的无参数构造函数。 是构造函数分配内存,还是编译器为实例“分配”内存然后调用构造函数? 这个答案是非常错误的...... 1 /构造函数不分配任何内存,它初始化它。 2/ 问题是关于内置的,而这个答案是关于父类的……这个错误的离题答案怎么得了 8 票? 分配内存?这是哪里来的? 我觉得有趣的是,这有 9 个赞成票和 5 个反对票,而排名靠前的答案有 5 个赞成票和 0 个反对票。

以上是关于默认构造函数是不是初始化内置类型?的主要内容,如果未能解决你的问题,请参考以下文章

默认初始化值初始化

构造函数与默认构造函数

拷贝构造函数

C++的默认构造函数与构造函数

用户定义的构造函数和隐式默认构造函数

new和delete,p150