I've defined a POD that I'm planning on using as an immutable data store. To accomplish this, I've qualified its members as const
, and am expecting to value-initialize instances (and zero-initialize in some cases). Consider the following code:
struct Foo
{
const int value;
};
int main()
{
Foo foo{ };
return 0;
}
When I try to zero-initialize this POD, I get a compiler error in Visual Studio (C3852) because of the const
qualifier on Foo::value
. If I remove the qualifier, the code compiles fine.
The exact error message is:
error C3852: 'Foo::value' having type 'const int': aggregate initialization could not initialize this member const members cannot be default initialized unless their type has a user defined default constructor
According to the standard (draft n3337), §8.5/5 (zero-initialization):
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;
— if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zeroinitialized and padding is initialized to zero bits;
— if T is an array type, each element is zero-initialized;
— if T is a reference type, no initialization is performed.
and §8.5/6 (default-initialization):
To default-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, no initialization is performed. If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
and §8.5/7 (value-initialization):
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.
My reading of the standard leads me to believe that my POD should be zero-initialized; not default-initialized. Am I misunderstanding the initialization process described in the standard?
EDIT: Considering the details provided in the accepted answer and related comments, this looks like a potential bug in the VS implementation (i.e., the implementation may be based on an outdated version of the standard). I've created a Microsoft Connect ticket to track this, which can be found here:
Foo foo{ };
. This is aggregate-initialization with less initializers than members, meaning that the data member will be initialized from an empty{}
. - dyp{}
is always list-init, and at least in later drafts (>= n3485), aggregate init is the first possible option of list-init. n3337 still has value-init before aggregate-init in list-init, though. See the resolution of CWG DR 1301 - dyp