Member not zeroed, a clang++ bug?

我只是一个虾纸丫 提交于 2019-11-28 23:27:45

Clang is correct, per the C++11 standard plus relevant DRs

In the original C++11 specification, B{} would perform value-initialization, resulting in a.i being zero-initialized. This was a change in behavior compared to C++98 for cases like

B b = {};

... which were handled as aggregate initialization in C++98 but treated as value-initialization in C++11 FDIS.

However, the behavior in this case was changed by core issue 1301, which restored the C++98 behavior by mandating that aggregate initialization is used whenever an aggregate is initialized by a braced-init-list. Since this issue is considered a DR, it is treated as de facto applying to earlier revisions of the C++ standard, so a conforming C++11 compiler would be expected to perform aggregate initialization here rather than value-initialization.

Ultimately, it's a bad idea to rely on value-initialization to initialize your data members, especially for a class that has user-provided constructors.

It does indeed look like a bug (or, as pointed out in the comments, behaving according to C++03 despite specifying C++11). In C++11, value-initialisation should zero the members of a before calling its default constructor. Initialisation of B is governed by this rule of 8.5/7

if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.

The zero-initialisation should recursively zero-initialise a per this rule of 8.5/5

if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized

and, of course, zero-initialisation of a should set i to zero.

It is not a compiler bug, it is a bug in your code. The compiler seems to be implementing the C++03 behaviour, but this has crucially changed in C++11.

These are some relevant quotes from the C++03 and C++11 standards

In C++03:

To value-initialize an object of type T means:

— 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);

if T is a non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;

(emphasis mine)

In C++11:

To value-initialize an object of type T means:

— if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);

— if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.

and

To zero-initialize an object or reference of type T means:

— if T is a scalar type (3.9), the object is set to the value 0 (zero), taken as an integral constant expression, converted to T;

  • if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized and padding is initialized to zero bits;

Note: The following only applies to C++03:

Either remove A's user-provided constructor, or change it to

A() : i() {}

When you value-initialize a B here,

B* p = new B {};

it value-initializes its data members. Since A has a default constructor, the value-initialization results in a call to that. But that constructor does not explicitly initialize A::i, so it gets default-initialized, which for an int means no initialization is performed.

If you had not provided a default constructor for A, then the data member would get zero-initialized when an A is value-initialized.

Integral types are not required to be initialized to a value like that in a non-default constructor (since you have provided a constructor)

Change your constructor to A() : i(0) {}.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!