为什么在堆中创建对象或在堆栈中创建临时对象时,结构体中的 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;
}
我得到以下输出:
[STACK] Num: -1079504552
[HEAP] Num: 0
[TEMP] Num: 0
这是编译器特定的行为吗?我并不是真的打算依赖这个,但我很好奇为什么会发生这种情况,特别是对于第三种情况。
The standard and the C++ book say that the default constructor for class type members is called by the implicit generated default constructor, but built-in types are not initialized. However, in this test program I get unexpected results when allocating an object in the heap or when using a temporary object:
#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;
}
I get this output:
[STACK] Num: -1079504552
[HEAP] Num: 0
[TEMP] Num: 0
Is this some compiler specific behaviour? I don't really intend to rely on this, but I'm curious to know why this happens, specially for the third case.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是预期的行为。有两个概念,“默认初始化”和“值初始化”。如果您没有提及任何初始化程序,则该对象是“默认初始化”的,而如果您确实提及它,即使作为默认构造函数的 () ,该对象也是“值初始化”的。当定义构造函数时,两种情况都会调用默认构造函数。但对于内置类型,“值初始化”会将内存清零,而“默认初始化”则不会。
因此,当您初始化时:
如果提供了默认构造函数,它将调用默认构造函数,但原始类型将未初始化。但是,当您提到初始值设定项时,例如
原始类型(或结构的原始成员)将被 VALUE 初始化。
类似地,
如果您定义构造函数,则
x 成员将未初始化,但如果您定义构造函数,
它将被 VALUE 初始化。这也适用于 new,因此
应该为您提供未初始化的内存,但
应该为您提供初始化为零的内存。
语法:
不幸的是,由于语法歧义,
是不允许的,并且如果它们都被指定并且不可内联,则必须调用默认构造函数后跟复制构造函数。
C++11 引入了新语法,
可用于这两种情况。如果您仍然坚持旧标准,这就是 Boost.ValueInitialized 的原因,这样您就可以正确初始化模板参数的实例。
可以在 Boost.ValueInitialized 文档中找到更详细的讨论。
It's expected behaviour. There are two concepts, "default initialization" and "value initialization". If you don't mention any initializer, the object is "default initialized", while if you do mention it, even as () for default constructor, the object is "value initialized". When constructor is defined, both cases call default constructor. But for built-in types, "value initialization" zeroes the memory whereas "default initialization" does not.
So when you initialize:
it will call default constructor if one is provided, but primitive types will be uninitialized. However when you mention an initializer, e.g.
a primitive type (or primitive members of a structure) will be VALUE-initialized.
Similarly for:
if you define the constructor
the x member will be uninitialized, but if you define the constructor
it will be VALUE-initialized. That applies to
new
as well, soshould give you uninitialized memory, but
should give you memory initialized to zero.
Unfortunately the syntax:
is not allowed due to grammar ambiguity and
is obliged to call default constructor followed by copy-constructor if they are both specified and non-inlineable.
C++11 introduces new syntax,
which is usable for both cases. If you are still stuck with older standard, that's why there is Boost.ValueInitialized, so you can properly initialize instance of template argument.
More detailed discussion can be found e.g. in Boost.ValueInitialized documentation.
简短的答案是:空括号执行值初始化。
当您改为使用
Container *pc = new Container;
时,您会观察到不同的行为。The short answer is: the empty parenthesis perform value initialization.
When you say
Container *pc = new Container;
instead, you will observe different behavior.