Deepak
Deepak

Reputation: 480

default constructor initialisation

Consider this code:

class First
{
public:
    int y;
    First()
    {
        y = 90;
    }
};

class Second{
    public:
       int x;
       First ob;  //if i comment it, value of x is initialised to zero
};

int main()
{
    Second obj = Second();
    cout << obj.x << endl;
}

This program gives different output when I change it:

  1. If I comment out the line First ob; then value of x is initialised to zero
  2. If the class consists object of class First, then member has garbage value.
  3. If I create object like Second obj; then it has garbage value.

What is the reason it behaves differently when Second class consists only built-in members and when object of another class?

And what is the difference between these statements:

Second obj = Second();
Second obj;

Upvotes: 0

Views: 182

Answers (3)

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361322

Case 1. When you comment out the line First ob, then Second class becomes a POD type, which can be value-initialized using the syntax Second obj= Second(), and value-initialization, in case of built-in types, means zero-initialized, so x is zero-initialized.

Case 2: When you keep the line First ob, then Second class becomes non-POD type, because First class is non-POD type (as it has user-defined constructor1]). In this case, the syntax Second obj=Second() doesn't initialize built-in data type, if you don't initialize it in the constructor.

Case 3: When write Second obj, then there are again two cases (read them carefully):

  • obj will be default constructed if there is First ob line. And in this case, x will not be initialized at all, as it is not manually initialized in the constructor of Second.

  • obj will not be initialized at all if you First ob line is commented out. In this case, Second becomes a POD, and POD types are not initialized if you only write Second obj.


1 See this related topic:

Upvotes: 3

Kerrek SB
Kerrek SB

Reputation: 476970

At the risk of being a bit tangential, let me post a modified version of the problem, along with a discussion. Let's consider these classes:

struct Agatha
{
    int x;
};

struct Claire
{
    Claire() { }
    int x;
};

To simplify the initialization syntax and make the example analyzable with Valgrind, let's use dynamic objects:

#include <memory>
#include <iostream>

int main()
{
    std::unique_ptr<Agatha> p1(new Agatha);     // #1d
    std::unique_ptr<Agatha> p2(new Agatha());   // #1v

    std::unique_ptr<Claire> q1(new Claire);     // #2d
    std::unique_ptr<Claire> q2(new Claire());   // #2v


    std::cout << p1->x
              << p2->x
              << q1->x
              << q2->x
              << std::endl;
}

Only one of those printing lines is correct! Can you figure out which one?

The answer is #1v. Let's discuss:

  • Case #1d default-initializes an aggregate, which default-initializes each member, which default-initializes Agatha::x, which leaves it uninitialized.

  • Case #1v value-initializes a aggregate, which value-initializes all members, and thus value-initializes Agatha::x, and thus zero-initializes it. (This is the good case.)

  • Case #2d default-initializes a non-aggregate, which calls the default constructor. The default constructor of Claire does not initialize Claire::x, so it is left uninitialized.

  • Case #2d value-initialization of a non-aggregate also calls the default constructor, and the situation is identical to #2v.

Notice that the whole discussion has nothing to do with PODness, but merely with whether the class is an aggregate, like Agatha, or a non-trivial class type with like Claire. You could add a member of type std::string to Agatha without affecting this example.

Upvotes: 1

je4d
je4d

Reputation: 7838

Have a read through the accepted answer to Do the parentheses after the type name make a difference with new? - without the First object, your class is an 'A', with it your class is a 'B'. Second obj; will default-initialize it, Second obj = Second(); will value-initialize it.

This is one of the areas where C++ has some quite tricky and surprising rules, but I'm not going to cover them in detail here as they've been very well explained in the above question.

What do the following phrases mean in C++: zero-, default- and value-initialization? is also related.

Edit:

The above links only really cover the initialization side of things, not the rules on what makes a class trivial/POD/standard layout/etc. What are Aggregates and PODs and how/why are they special? covers that side of things.

Upvotes: 1

Related Questions