I'm trying to nail down the differences between N3337 §8.5p7 (C++11) and N3797 §8.5p8 (post C++11) that deal with value-initialization.
N3337 §8.5p7:
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.
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.
N3797 §8.5p8:
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.
Given these two rules the snippet below should give different results:
#include <iostream>
struct Base {
int i;
Base(int i):i(i) {}
Base():i(10) {}
};
struct Derived : public Base {
int j;
Derived(int j):Base(j), j(j) {}
Derived()=default;
};
int main() {
Derived d{};
std::cout << "d.i = " << d.i << " " << "d.j = " << d.j << '\n';
}
as follows:
- According to N3337, the default constructor for
Derived
is called, asDerived
has a user-provided constructor. The default constructor forDerived
callsBase
default constructor, which initializesDerived::i = 10
, leavingDerived::j
unitialized. - From N3797, as
Derived
has no user-provided default constructor, nor a deleted default constructor, the second bullet point applies. That is,Derived
is zero-initialized, i.e., bothDerived::i
andDerived::j
are initialized with 0 and the objectd
is default-initialized, which leavesDerived::i = 10
.
Although my knowledge of Unixes is minimum, I've been trying to replicate these two cases, using different flags for the compilers clang++ and g++, by trial and error, in Coliru, to no avail. The results so far, all printed d.i = 10 d.j = 0
without warnings.