Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does "ctor() = default" change behavior when other constructors are present?

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?

like image 471
user541686 Avatar asked Dec 24 '14 22:12

user541686


People also ask

What is ctor in constructor?

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.

Is default constructor created automatically?

The default constructor is auto-generated if there is no user-declared constructor (§12.1/5).

Why are default constructors used?

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.

What is an automatic default constructor and what does it do?

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.


2 Answers

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 literal 0 (zero) to T;

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.

like image 199
David G Avatar answered Oct 13 '22 01:10

David G


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.

like image 21
Ryan Haining Avatar answered Oct 13 '22 00:10

Ryan Haining