41

My question somewhat overlaps with this and several other similar ones. Those have some great answers, but I've read them and I'm still confused, so please don't consider this question a duplicate.

So, I have the following code:

class A {
    public: int _a;
}

void main()
{
    A inst1;
    A* inst2 = new A;
    A* inst3 = new A();
}

_a is left uninitialized in inst1 and inst2 and is initialized to 0 in inst3. Which initialization is called which, and why does the code work as it does? Please take into I account I don't have a C++ 03 standard at hand, but I have the last C++ 11 draft (I'm programming by '03 standard, though), so quotations of the '03 standard or references to '11 are most welcome.

P. S. The original task behind this research was to correctly zeto-initialize a member of arbitrary template type T.

Community
  • 1
  • 1
Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
  • possible duplicate of [Value-initializing an automatic object?](http://stackoverflow.com/questions/6298001/value-initializing-an-automatic-object) – Ben Voigt Nov 12 '11 at 17:18
  • for upcoming users check this too https://stackoverflow.com/questions/6032638/default-variable-value – Abhishek Mane Dec 05 '21 at 06:17

2 Answers2

48

Not so hard:

A x;
A * p = new A;

These two are default initialization. Since you don't have a user-defined constructor, this just means that all members are default-initialized. Default-initializing a fundamental type like int means "no initialization".

Next:

A * p = new A();

This is value initialization. (I don't think there exists an automatic version of this in C++98/03, though in C++11 you can say A x{};, and this brace-initialization becomes value-initialization. Moreover, A x = A(); is close enough practically despite being copy-initialization, or A x((A())) despite being direct-initialization.)

Again, in your case this just means that all members are value-initialized. Value initialization for fundamental types means zero-initialization, which in turn means that the variables are initialized to zero (which all fundamental types have).

For objects of class type, both default- and value-initialization invoke the default constructor. What happens then depends on whether default constructor is compiler or user defined. If user defined, in both default- and value-initialization behave the same way and what happens depends on the constructor's initializer list, and the game continues recursively for member variables. If compiler defined, default and value initialization behave as expected.

Hari
  • 1,561
  • 4
  • 17
  • 26
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • I understand how it works for classes (they have constructors, either explicitly defined or default). Only built-in type objects got me confused. Thanks for the explanation. However, I didn't get the comment about copy-initialization and direct initialization. Haven't you mixed them up? – Violet Giraffe Nov 12 '11 at 18:00
  • @VioletGiraffe: I hope not. Don't confuse "initialization", which is a grammatical concept, with "construction", which is part of the object model. The former sometimes causes the latter, but there's some overlapping and confusing terminology at work. – Kerrek SB Nov 12 '11 at 18:01
  • Should `A x = A((A()))` be `A x( A() );` instead? – K-ballo Nov 12 '11 at 18:02
  • @K-ballo: Most certainly no. Please try it for yourself and weep :-) – Kerrek SB Nov 12 '11 at 18:03
  • 1
    @Kerrek SB: Maybe `A x( (A()) );` then? Otherwise is still *copy-initialization* isn't it? – K-ballo Nov 12 '11 at 18:05
  • @Kerrek SB: OK, now I'm totally lost, I fail to see how a spare pare of parentheses make any difference. Oh, and I got the copy-initialization, scratch my previous question. I must admit, I didn't notice the `=`, which invokes a copy constructor. – Violet Giraffe Nov 12 '11 at 18:06
  • @K-ballo: Ah, now we're getting somewhere. Thanks, that was indeed wrong! Fixed... – Kerrek SB Nov 12 '11 at 18:06
  • @VioletGiraffe: I had a mistake, as K-Ballo pointed out. It should be: `A x((A()));`. That's direct-initialization, but it essentially boils down to value-initialization. You cannot omit the extra parentheses because of the C++ parsing rules. – Kerrek SB Nov 12 '11 at 18:08
  • @VioletGiraffe: Not at all :-) It's copy-initialization because it involves the equals-sign ("`=`"). Copy-initialization can result in any number of things, depending on what it is you're initializing. Like `int x = 5;`, which would result in the same code as direct-initialization `int x(5);`. On the other hand, `Foo x = 6;` would cause the constructor `Foo(6)` to be called, and `Foo x = Foo(6);` would almost certainly, too (though in GCC you can suppress this via `-fno-elide-constructors`). – Kerrek SB Nov 12 '11 at 18:15
  • But that's an optimization, isn't it? Shouldn't the plain naive approach involve copy constructor? – Violet Giraffe Nov 12 '11 at 18:21
  • @VioletGiraffe: I guess, but the standard does permit the elision of copy construction, even if the copy constructor has side effects. That's why I say "practically close enough". You have a similar issue with aggregates: `Foo x[] = { 1, 2, 3 };` vs. `Foo x[] = { Foo(1), Foo(2), Foo(3) };` – Kerrek SB Nov 12 '11 at 18:23
  • OK, I've run some tests. Now, could you please explain why exactly does `A x ( (A()))` call a constructor `A::A()`, and `A x ( A() )` doesn't? – Violet Giraffe Nov 12 '11 at 18:40
  • 1
    @VioletGiraffe: Because `A x(A())` declares `x` as a function returning `A` and taking one argument which itself is a (pointer to a) function returning `A` and taking no arguments. It's not what you were thinking you were declaring :-) – Kerrek SB Nov 12 '11 at 18:43
  • Got it, but how does another pair of braces change things? I thought nested adjacent braces are transparent (have no effect). – Violet Giraffe Nov 12 '11 at 19:04
  • Suppose if I have a class member `_x` of type `T`, and I write initializer list as follows: `_x ( T () ). If my understanding is correct, this is a direct initialization with a value-initialized object, so in the end _x will be 0 if `T` is of built-in type. Is that right? – Violet Giraffe Nov 12 '11 at 19:26
  • @VioletGiraffe: initializer lists are a different context. The C++ grammar has a few curious corner situations like that... in response to your previous question: parentheses mustn't surround type declarations, so `(A())` is parsed as an *expression* and all is well. – Kerrek SB Nov 12 '11 at 19:28
  • @KerrekSB if object is static or globally declared then it is value initialized right ? – Abhishek Mane Dec 05 '21 at 13:04
1

Yes, A inst4 (); is treated as a function declaration. std::string str(); should be the same (i.e. I think you mistakenly thought it worked).

Apparently (from here), C++03 will have inst3._a be 0, but C++98 would have left it uninitialized.

Community
  • 1
  • 1
John Zwinck
  • 239,568
  • 38
  • 324
  • 436