The snippet compiles with warnings in Coliru, but compiles normally in Ideone. Which one is correct?

c++, c++11, initialization, language-lawyer

Solution

There's a distinct difference in the behavior of value-initialization between C++11 and N3797 for classes with both a defaulted default constructor and another non-default constructor. C++11 § 8.5/7:

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.

- if T is an array type, then each element is value-initialized;

- otherwise, the object is zero-initialized.

N3797 § 8.5/8:

To value-initialize an object of type T means:

- if T is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;

- if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized;

- if T is an array type, then each element is value-initialized;

- otherwise, the object is zero-initialized.

Your `struct A` has a user-declared default constructor `A() = default;` and a user-provided non-default constructor `A(int j) : i{j} {}`. In C++11, it's subject to the first bullet: it has a user-provided constructor, so the default constructor is called (which does nothing: `A`'s default constructor is trivial). In N3797, the second bullet applies since `A` is "without a user-provided or deleted default constructor" so the object is zero-initialized.

Put simply, value-initialization in C++11 of an object of a class with any user-provided constructor will not perform zero-initialization before default-initialization. In N3797, value-initialization of an object of a class with no user-provided default constructor will perform zero-initialization before default-initialization.

It appears that the version of clang on Coliru has been tracking the standard here post-C++11, but GCC 4.8 has not.

EDIT: This test program demonstrates that GCC 4.8 actually does follow the N3797 rules for value initialization. The problem seems to be that it is default-initializing the array elements for which no initializer is provided instead of value-initializing them as required by the standard. Note the difference in behavior between the second array element, which is explicitly provided an empty initializer, and the third which is provided no initializer.

This is looking like a probable GCC bug.

EDIT: The same test program compiled by the same GCC version on Ideone doesn't demonstrate the bug. No idea what is going on here. Perhaps different compiler flags affecting the output on Ideone, I have no idea how to determine the compiler command line used.

Problem

This code compiles in Coliru with warnings [unitialized members `a[1].i` and `a[2].i` in the `std::cout <<` expression in `main()`] but compiles normally in Ideone. ``` #include <iostream> struct A { int i; A(int j) : i{j} {}; A() = default; }; int main() { A a[3] = { A(1) }; std::cout << a[1].i << ' ' << a[2].i << '\n'; } ``` According to my interpretation of iso § 8.5 p7, Ideone is correct, because of the 4th bullet point in this clause. This is § 8.5 p7 from N3797 To value-initialize an object of type T means: - if T is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized; - if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized; - if T is an array type, then each element is value-initialized; - otherwise, the object is zero-initialized. An object that is value-initialized is deemed to be constructed and thus subject to provisions of this International Standard applying to “constructed” objects, objects “for which the constructor has completed,” etc., even if no constructor is invoked for the object’s initialization.

Original source