C++ zero initialization – Why is `b` in this program uninitialized, but `a` is initialized?

  • A+

According to the accepted (and only) answer for this Stack Overflow question,

Defining the constructor with

MyTest() = default; 

will instead zero-initialize the object.

Then why does the following,

#include <iostream>  struct foo {     foo() = default;     int a; };  struct bar {     bar();     int b; };  bar::bar() = default;  int main() {     foo a{};     bar b{};     std::cout << a.a << ' ' << b.b; } 

produce this output:

0 32766 

Both constructors defined are default? Right? And for POD types, the default initialization is zero-initialization.

And according to the accepted answer for this question,

  1. If a POD member is not initialized in the constructor nor via C++11 in-class initialization, it is default-initialized.

  2. The answer is the same regardless of stack or heap.

  3. In C++98 (and not afterward), new int() was specified as performing zero initialization.

Despite trying to wrap my (albeit tiny) head around default constructors and default initialization, I couldn't come up with an explanation.


The issue here is pretty subtle. You would think that

bar::bar() = default; 

would give you a compiler generated default constructor, and it does, but it is now considered user provided. [dcl.fct.def.default]/5 states:

Explicitly-defaulted functions and implicitly-declared functions are collectively called defaulted functions, and the implementation shall provide implicit definitions for them ([class.ctor] [class.dtor], [class.copy.ctor], [class.copy.assign]), which might mean defining them as deleted. A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration. A user-provided explicitly-defaulted function (i.e., explicitly defaulted after its first declaration) is defined at the point where it is explicitly defaulted; if such a function is implicitly defined as deleted, the program is ill-formed. [ Note: Declaring a function as defaulted after its first declaration can provide efficient execution and concise definition while enabling a stable binary interface to an evolving code base. — end note ]

emphasis mine

So we can see that since you did not default bar() when you first declared it, it is now considered user provided. Because of that [dcl.init]/8.2

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;

no longer applies and we are not value initializing b but instead default initializing it per [dcl.init]/8.1

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


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: