Why does
struct wrapper
{
explicit wrapper(void *);
wrapper() = default;
int v;
};
int main() { return wrapper().v; } // You should run this in Debug mode
return 0xCCCCCCCC
, whereas
struct wrapper { wrapper() = default; int v; };
int main() { return wrapper().v; }
and
struct wrapper { int v; };
int main() { return wrapper().v; }
both return 0
?
In class-based, object-oriented programming, a constructor (abbreviation: ctor) is a special type of subroutine called to create an object. It prepares the new object for use, often accepting arguments that the constructor uses to set required member variables.
The default constructor is auto-generated if there is no user-declared constructor (§12.1/5).
They are used to initialize member objects. If default values are supplied, the trailing arguments can be omitted in the expression list of the constructor. Note that if a constructor has any arguments that do not have default values, it is not a default constructor.
In computer programming languages, the term default constructor can refer to a constructor that is automatically generated by the compiler in the absence of any programmer-defined constructors (e.g. in Java), and is usually a nullary constructor.
During value-initialization, if T
is a class type without a user-provided or deleted default-constructor, then the object is zero-initialized (§8.5/8.2). This is indeed the case with wrapper
.
Your first example matches the third case for zero-initialization (§8.5/6.1, emphasis mine)
— if
T
is a scalar type (3.9), the object is initialized to the value obtained by converting the integer literal0
(zero) toT
;— if
T
is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class sub-object 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 zero-initialized 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
So in your first example, v
should be zero-initialized. This looks like a bug.
In your second and third example you no longer have a user-provided constructor, but you do have a default-constructor that isn't user-provided or deleted so your example still falls into the third case for zero-initialization, which is to zero-initialize each non-static data member. VS is correct there.
This does appear to be a bug in MSVC. In all three cases wrapper
has no user-provided default constructor, so initialization with wrapper()
invokes:
(All citations from n3690)
(8.5/11) An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
(thanks to dyp), this will result in zero-intialization of int v
Initialization then refers us to the rule:
(8.5/8) 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.
The zero initialization rules state:
(8.5/6) 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
int v
being a data member of wrapper
is zero initialiazed itself according to:
(8.5/6) if T is a scalar type (3.9), the object is initialized to the value obtained by converting the integer literal 0 (zero) to T
Which is not the behavior you observe.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With