Narek
Narek

Reputation: 39871

C++ object construction with garbage, why?

I have had the following structure:

struct MyStruct
{
    struct Displacement
    {
        bool            isWrapped;
        int             steps;
    };

    int                     initialDuration;
    int                     currentDuration;
    Displacement            displacement1;
    Displacement            displacement2;
};

And I was using it like this:

MyStruct obj{2, 2};
auto shared = std::make_shared<MyStruct>(obj);

The problem was that I needed to duplicate first two arguments as initialDuration and currentDuration should be the same when a new object is created. Therefore I have created a CTOR:

struct MyStruct
{
    struct Displacement
    {
        bool            isWrapped;
        int             steps;
    };

    MyStruct(int duration) 
          : initialDuration(duration)
          , currentDuration(duration)
    {
    }

    int                     initialDuration;
    int                     currentDuration;
    Displacement            displacement1;
    Displacement            displacement2;
};

and then used like this:

    auto shared = std::make_shared<MyStruct>(2);

The unexpected thing 1 is: both Displacement members of MyStruct have been initialized with garbage. For one the bool member of true, for the other one - false and ints were some arbitrary numbers.

So though maybe I need to define CTOR for Displacement too. Defined like this:

    struct Displacement
    {
        Displacement() : isWrapped(false), steps(0) {}

        bool            isWrapped;
        int             steps;
    };

The unexpected thing 2 is: that somewhere else

  MyStruct::Displacement d {false, 0}; 

started to not compile. I don't know aggregate initialization or list-initialization stopped working for a POD struct when I have defined the default CTOR.

Please explain the reasons of those 2 behaviours.

Upvotes: 2

Views: 790

Answers (3)

songyuanyao
songyuanyao

Reputation: 172924

For your 1st question

both Displacement members of MyStruct have been initialized with garbage.

(from comment) There should be a default CTOR for Displacement defined by the compiler which should be called in the CTOR of MyStruct that I have defined, right?

The implicitly-defined default constructor won't do anything here.

If the implicitly-declared default constructor is not defined as deleted, it is defined (that is, a function body is generated and compiled) by the compiler, and it has exactly the same effect as a user-defined constructor with empty body and empty initializer list. That is, it calls the default constructors of the bases and of the non-static members of this class.

And for MyStruct obj{2, 2};, obj is an automatic object, so (from standard $8.5/12 Initializers [dcl.init])

If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced (5.18). [ Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2. — end note ]

You might want to initialize them as

MyStruct obj{2, 2, {false, 0}, {false, 0}};

For your 2nd question

I don't know aggregate initialization or list-initialization stopped working for a POD struct when I have defined the default CTOR.

Yes it does, unless you provide another ctor which takes std::initializer_list as its parameter. See aggregate initialization

An aggregate is an object of the type that is one of the following

array type  
class type (typically, struct or union), that has  
    no private or protected non-static data members
    no user-provided constructors (explicitly defaulted or deleted constructors are allowed) (since C++11)
    no base classes
    no virtual member functions 
    no default member initializers (since C++11) (until C++14)

Upvotes: 2

Some programmer dude
Some programmer dude

Reputation: 409176

If you have a constructor that is called you need to explicitly initialize all members, or they will be uninitialized. Uninitialized members will have indeterminate values which is what you perceive as garbage. That's how C++ work when you have constructors.

From this implicit default constructor reference:

If the implicitly-declared default constructor is not defined as deleted, it is defined ... by the compiler, and it has exactly the same effect as a user-defined constructor with empty body and empty initializer list. That is, it calls the default constructors of the bases and of the non-static members of this class.

Built-in or aggregate types have no constructor, and so can't be constructed or initialized without an explicit initialization.

Upvotes: 2

Kurt Stutsman
Kurt Stutsman

Reputation: 4034

Your struct is no longer a POD type when you add a default constructor. Among other things, a POD type must have a trivial default constructor.

You need to add a constructor that takes two arguments for your code to start working again. Also note that the default constructor does not 0-initialize members. The reason it worked before with the POD type is that doing aggregate initialization (which only works with POD types) defaults members not explicitly initialized to 0.

Upvotes: 1

Related Questions