为什么在堆中创建对象或在堆栈中创建临时对象时,结构zero中的POD由隐式构造函数初始化? 标准和C++书中说,类类型成员的默认构造函数是隐式生成的默认构造函数调用的,但内置类型没有初始化。但是,在这个测试程序中,当在堆中分配对象或使用临时对象时,我得到了意外的结果: #include<iostream> struct Container { int n; }; int main() { Container c; std::cout << "[STACK] Num: " << c.n << std::endl; Container *pc = new Container(); std::cout << "[HEAP] Num: " << pc->n << std::endl; delete pc; Container tc = Container(); std::cout << "[TEMP] Num: " << tc.n << std::endl; }

为什么在堆中创建对象或在堆栈中创建临时对象时,结构zero中的POD由隐式构造函数初始化? 标准和C++书中说,类类型成员的默认构造函数是隐式生成的默认构造函数调用的,但内置类型没有初始化。但是,在这个测试程序中,当在堆中分配对象或使用临时对象时,我得到了意外的结果: #include<iostream> struct Container { int n; }; int main() { Container c; std::cout << "[STACK] Num: " << c.n << std::endl; Container *pc = new Container(); std::cout << "[HEAP] Num: " << pc->n << std::endl; delete pc; Container tc = Container(); std::cout << "[TEMP] Num: " << tc.n << std::endl; },c++,constructor,initialization,default-constructor,object-initialization,C++,Constructor,Initialization,Default Constructor,Object Initialization,这是编译器特有的行为吗?我真的不想依赖这一点,但我很想知道为什么会发生这种情况,特别是第三种情况。这是预期的行为。有两个概念,“默认初始化”和“值初始化”。如果您没有提到任何初始值设定项,那么对象是“默认初始化的”,而如果您提到它,即使是默认构造函数的(),对象也是“值初始化的”。定义构造函数时,这两种情况都调用默认构造函数。但对于内置类型,“值初始化”会将内存归零,而“默认初始化”则不会 因此,在初始化时: Type x; 如果提供了默认构造函数,它将调用默认构造函数,但原语类型将被取消初始

这是编译器特有的行为吗?我真的不想依赖这一点,但我很想知道为什么会发生这种情况,特别是第三种情况。

这是预期的行为。有两个概念,“默认初始化”和“值初始化”。如果您没有提到任何初始值设定项,那么对象是“默认初始化的”,而如果您提到它,即使是默认构造函数的(),对象也是“值初始化的”。定义构造函数时,这两种情况都调用默认构造函数。但对于内置类型,“值初始化”会将内存归零,而“默认初始化”则不会

因此,在初始化时:

Type x;
如果提供了默认构造函数,它将调用默认构造函数,但原语类型将被取消初始化。然而,当你提到初始值设定项时,例如

Type x = {}; // only works for struct/class without constructor
Type x = Type();
Type x{}; // C++11 only
原语类型(或结构的原语成员)将进行值初始化

同样适用于:

struct X { int x; X(); };
如果您定义构造函数

X::X() {}
X::X() : x() {}
x成员将被取消初始化,但如果您定义构造函数

X::X() {}
X::X() : x() {}
它将被初始化。这也适用于新的,所以

new int;
应该给你未初始化的内存,但是

new int();
应该给你初始化为零的内存。 不幸的是,语法:

Type x();
由于语法歧义和

Type x = Type();
如果它们都是指定的且不可内联的,则必须调用默认构造函数,后跟复制构造函数

C++11引入了新的语法

Type x{};
这两种情况下都可用。若您仍然使用旧的标准,那个么这就是为什么会有Boost.ValueInitialized,这样您就可以正确地初始化模板参数的实例


可以找到更详细的讨论,例如…

简短的回答是:空括号执行


当你说
Container*pc=newcontainer时
相反,您将观察到不同的行为。

我的猜测可能重复,堆本身是用零初始化的。我认为堆的情况也是如此,可能只是碰巧是零,但我发现临时对象的情况令人惊讶。请参阅@sharptooth发布的链接,它解释了临时情况,大多数操作系统作为一种安全措施,在将内存页处理到进程之前会将其归零(以避免进程能够检查其他进程的内存)。这样做的结果往往是,一个简单的测试用例,只要mallocs就可以得到初始化的内存(不是真的,但看起来会是这样),而堆栈被以前的函数调用修改的几率更大。@FredOverflow,对,但我的gcc初始化POD类型为0,有括号或没有括号。@Ashot:这是巧合,也发生在我的机器上。只需在堆上再创建几个不带括号的值,就会得到不同的值。@FredOverflow在分配了大量内存后,我终于得到了非零数据:)谢谢。@Ashot Martirosyan:您可以执行此测试,看看它是否真的在初始化:
struct test{int x;};void foo(){test t;std::cout@Ashot Martirosyan:如果对一个方法的每次调用都需要额外的内存,那么堆栈很容易溢出:
for(int i=0;i<100000000;++i){foo();}
。对
foo()
的每次调用都会从堆栈中得到自己的一部分,当函数返回时就会释放它(通常是调用方,但这是一个实现细节)。对同一函数的连续调用应该重用堆栈的同一部分。您是否向测试添加了任何代码?您使用的编译器是什么?上面的代码以g++显示了预期的结果。回答得很好,但是关于std::make_unique(),它会初始化变量值吗?