默认构造函数是否总是初始化所有成员? [英] Does a default constructor always initialize all members?
问题描述
我发誓我不记得以前看过这个,而且我难以相信自己的眼睛:
I could swear I don't remember having seen this before, and I'm having trouble believing my eyes:
为a做一个隐式定义的默认构造函数非聚集类是否初始化其成员?
Does an implicitly-defined default constructor for a non-aggregate class initialize its members or no?
在Visual C ++中,当我运行此看起来无害的代码时...
In Visual C++, when I run this innocent-looking code...
#include <string>
struct S { int a; std::string b; };
int main() { return S().a; }
...令我惊讶的是,它返回的非零值!但是,如果删除字段 b
,则它返回零。
... to my astonishment, it returns a non-zero value! But if I remove field b
, then it returns zero.
我已经在所有VC ++版本上尝试过此操作我可以动手,而且似乎可以对所有这些进行操作。
I've tried this on all versions of VC++ I can get my hands on, and it seems to do this on all of them.
但是,当我在Clang和GCC上尝试使用时,值初始化为零,不管我是在C ++ 98模式还是C ++ 11模式下尝试。
But when I try it on Clang and GCC, the values are initialized to zero, whether I try it in C++98 mode or C++11 mode.
正确的行为是什么?
推荐答案
引用C ++ 11:
5.2.3显式类型转换(功能符号)[expr.type.conv]
2表达式 T()
,其中 T
是简单类型说明符或类型名称说明符对于非数组完整对象类型或(可能具有cv资格的) void
类型,将创建指定类型的prvalue,并对其进行值初始化(8.5; void()
的情况下不会进行初始化)。 [...]
2 The expression T()
, where T
is a simple-type-specifier or typename-specifier for a non-array complete object type or the (possibly cv-qualified) void
type, creates a prvalue of the specified type,which is value-initialized (8.5; no initialization is done for the void()
case). [...]
8.5初始化程序[dcl.init]
7要 value-initialize T
类型的对象的意思是:
7 To value-initialize an object of type T
means:
- ...
- 如果
T
是(可能具有cv限定)非工会类类型,并且没有用户提供的构造函数,则该对象将初始化为零,并且T
的隐式声明的默认构造函数很简单,即调用该构造函数。 - ...
- ...
- if
T
is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, ifT
's implicitly-declared default constructor is non-trivial, that constructor is called. - ...
因此在C ++ 11中, S()。a
应该为零:在调用构造函数之前,该对象已初始化为零,并且构造函数不会将 a
的值更改为其他任何值。
So in C++11, S().a
should be zero: the object is zero-initialized before the constructor gets called, and the constructor never changes the value of a
to anything else.
在C ++ 11之前,值初始化有不同的描述。引用N1577(大致为C ++ 03):
Prior to C++11, value initialization had a different description. Quoting N1577 (roughly C++03):
要对值T的对象进行值初始化的意思是:
- ...
- 如果
T
是非工会类类型如果没有用户声明的构造函数,则T
的每个非静态数据成员和基类组件都将进行值初始化; - ...
- 否则,对象将初始化为零
- ...
- if
T
is a non-union class type without a user-declared constructor, then every non-static data member and base-class component ofT
is value-initialized; - ...
- otherwise, the object is zero-initialized
此处, S
的值初始化未调用任何构造函数,但导致其 a
和 b
个成员。然后,该 a
成员的值初始化导致该特定成员的初始化为零。在C ++ 03中,结果也保证为零。
Here, value initialization of S
did not call any constructor, but caused value initialization of its a
and b
members. Value initialization of that a
member, then, caused zero initialization of that specific member. In C++03, the result was also guaranteed to be zero.
甚至早于此,使用第一个标准C ++ 98:
Even earlier than that, going to the very first standard, C++98:
表达式
T()
,其中T
是对于非数组完整对象类型或(可能经过cv限定)void
类型的simple-type-specifier (7.1.5.2),会创建一个右值指定的类型,其值由默认初始化确定(8.5;void()
情况不进行初始化)。
The expression
T()
, whereT
is a simple-type-specifier (7.1.5.2) for a non-array complete object type or the (possibly cv-qualified)void
type, creates an rvalue of the specified type, whose value is determined by default-initialization (8.5; no initialization is done for thevoid()
case).
要默认初始化类型为<的对象code> T 的意思是:
- 如果
T
是非POD类类型(第9节),将调用T
的默认构造函数(如果T $ c,则初始化格式不正确。 $ c>没有可访问的默认构造函数);
- ...
- 否则,该对象的存储将初始化为零。
- if
T
is a non-POD class type (clause 9), the default constructor forT
is called (and the initialization is ill-formed ifT
has no accessible default constructor); - ...
- otherwise, the storage for the object is zero-initialized.
因此基于第一个标准,VC ++是正确的:当您添加 std :: string
成员时, S
变为非POD类型,并且非POD类型不会初始化为零,它们只是调用了其构造函数。为 S
隐式生成的默认构造函数不会初始化 a
成员。
So based on that very first standard, VC++ is correct: when you add a std::string
member, S
becomes a non-POD type, and non-POD types don't get zero initialization, they just have their constructor called. The implicitly generated default constructor for S
does not initialise the a
member.
因此可以说所有编译器都是正确的,只是遵循该标准的不同版本。
So all compilers can be said to be correct, just following different versions of the standard.
正如@Columbo在评论中所报告的那样,更高版本的VC ++确实会导致 a
成员要初始化,以符合C ++标准的最新版本。
As reported by @Columbo in the comments, later versions of VC++ do cause the a
member to be initialized, in accordance with more recent versions of the C++ standard.
这篇关于默认构造函数是否总是初始化所有成员?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!