Reputation: 39871
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 int
s 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
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
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
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