Default initialization confusion - c++

In my C++ Primer, 5th Edition, they say on page 43 about default initialization (emphasis mine):
The value of an object of built-in type that is not explicitly initialized depends on where it is defined. Variables defined outside any function body are initialized to zero.
Later, on page 73, they define a new class like this:
struct Sales_data {
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
This is supposed to provide an example of the new standard's in-class initializers. In this case, units_sold and revenue will be initialized to zero. If they are not, they say, the variables will be default-initialized.
But this is my question: What is the point of this in-class initialization? What's wrong with letting them just default-initialize? The reason I ask is that they already mentioned that variables defined outside any function body are initialized to zero, and in this case, these variables are not inside any function - they are in a class definition. So the default-initialization should initialize these variables to zero, shouldn't it?

The quote seems to be in wrong context. A variable can have at least 3 states:
Default initialized: Variable is initialized inside the constructor
based on argument or no argument. Value initialized is a special case of this type
In-class initialized: The C++11 feature which you have presented in
your code
Uninitialized: Variable's initialization is not addressed anywhere
and it can contain any garbage value. Some compilers may automatically make it 0 or give a warning

The first statement about "Variables defined outside any function body" refers to objects with static linkage, i.e., variables declared in namespaces: These are zero initialized. The members in the struct get initialized wherever this struct lives. If it lives on the stack or is allocated on the heap, the built-in variable won't get initialized without the assignments, e.g., when used like this:
void f() {
Sales_data data;
}
Even without the initialization in the declaration, they would get zero-initialized if the struct is used like this, though:
Sales_data global; // <--- the "outside any function body" case
void f() {
Sales_data data0 = {};
Sales_data data1 = Sales_data();
Sales_data data2{};
}
However, these all require cooperation by the user of the struct and initializing them explicitly makes sure the values are set.

Related

C++: Are local automatic variables initialized or not? Stroustrup example

The following example is from Stroustrup C++ 4th Ed. Page 519. It was my understanding from K&R C and earlier in the Stroustrup book that local automatic variables of primitive types are undefined or not known to be initialized. Static variables of primitive types or automatic variables of a class with a default constructor are initialized.
That would mean int b should be undefined and not known to be initialized. Yet, Stroustrup adds the following code comment saying b = 0. Is this Errata? Or perhaps some behavior of calling with the default constructor?
Thank you
struct S {
string a;
int b;
};
void f(void) {
S s0 {}; // default construction: {"",0}
// ...
}
It's easy. You can leave the built-in type variables uninitialized or you can ask the compiler to zero-initialize them.
S s1; // string is default initialized, int is left uninitialized
S s2{}; // All fields are initialized.
Notice the {}. That (in this case) asks the compiler to initialize all fields.
In this line:
S s0 {};
the syntax that is used is value-initialization, in particular
when a named variable (automatic, static, or thread-local) is declared with the initializer consisting of a pair of braces.
In this case, the effect of value-initialization is that the object s0 is zero-initialized.
In this particular case, the effect is:
If T is an non-union class type, all base classes and non-static data members are zero-initialized, and all padding is initialized to zero bits. The constructors, if any, are ignored.
which implies that the int member b is zero-initialized to the value 0.
Are local automatic variables initialized or not?
It depends on the initialisation syntax that is used, the type of the variable, as well as the storage class.
That would mean int b should be undefined
No, because the example uses value initialisation, and the class in question is an aggregate.

Are pointer to a member of this allowed in object initialization?

From Aggregate initialization, set pointer to struct member, is the following code legal:
struct S
{
int a;
int* aptr;
};
S s = { 3, &s.a };
Quote from latest standard draft:
[basic.scope.pdecl]
The point of declaration for a name is immediately after its complete declarator ([dcl.decl]) and before its initializer (if any), except as noted below.
So, yes. The identifier s has already been declared, so it can be used in its initialiser.
Note that the value of s may not be used until it has been initialised. The value is not used in the example, so this is not a problem.
I'd also be curious about whether analogous code is valid when the two members of S are in reversed order
The order of members does not matter.

Comparison of member initialization by constructor vs. direct initialization

I'm creating a class in which one member is a const pointer (immutable address) to another member of the struct.
In the simplified version below, will both classes always behave the same value? Especially in the sense of whether the addresses stored in ptr are guaranteed to be properly initialized.
struct First
{
int a;
int* const ptr = &a;
};
struct Second
{
int a;
int* const ptr;
Second() : ptr(&a) {}
};
(In my actual application the member a is a class instance, and ptr is replaced by a map from some enums to pointers pointing to members of a.)
In the simplified version below, will both structs always behave the same way?
No they won't, but it may be ok for your case. Read on.
Both First::ptr and Second::ptr will be initialized to the expected value being the address of First::a and respectively Second::a, but:
[class.mem]/7 & [class.mem]/9
7 In a member-declarator, an = immediately following the declarator is interpreted as introducing a pure-specifier
if the declarator-id has function type, otherwise it is interpreted as introducing a brace-or-equal-initializer.
9 A brace-or-equal-initializer shall appear only in the declaration of a data member. (For static data members,
see 12.2.3.2; for non-static data members, see 15.6.2 and 11.6.1). A brace-or-equal-initializer for a non-static
data member specifies a default member initializer for the member, and shall not directly or indirectly cause
the implicit definition of a defaulted default constructor for the enclosing class or the exception specification
of that constructor.
This means, First has a defaulted default constructor where Second has a user-provided default constructor, which change some characteristic of those classes. I can for instance think of aggregates, triviality and maybe standard layouts.

Implicitly constructed variables in c++

I'm getting to grips with c++ and there's one language feature I'm having particular trouble getting my head around.
I'm used to declaring and initialising a variable explicitly, but in c++ we sometimes seem to declare and implicitly construct a variable.
For example in this snippet rdev seems to be implicitly constructed (as it is subsequently used to construct a default_random_engine);
random_device rdev;
default_random_engine gen(rdev());
Can someone explain what's going on here? How can I tell this apart from a simple declaration such as int myInt; ?
Can someone explain what's going on here?
These are definitions, not just declarations. A variable definition creates the variable. In the first case, there's no initialiser, indicating that it should be default-initialised.
How can I tell this apart from a simple declaration such as int myInt; ?
That's also a definition, creating the int variable and leaving it uninitialised.
You can declare a global variable without defining it:
extern int myInt;
extern indicates that it has external linkage, and is defined somewhere else. Other kinds of variable can't be declared without defining them.
random_device rdev; // creates an instance of random_device on the stack
// with default constructor (taking no arguments)
default_random_engine gen( // creates an instance of default_random_engine
// on the stack
rdev() // passing it the result of
// invocation of operator '()'
// on the instance rdev of random_device
);
Same in a more verbose form (with some C++11):
auto rdev = random_device {};
auto gen = default_random_engine { rdev.operator()() };
Can someone explain what's going on here? How can I tell this apart
from a simple declaration such as int myInt;
They are both simple definitions.
The only difference is the properties of the type. random_device needs to be constructed, so it is. int does but people cried too much, so it isn't. Frankly, int's behaviour is more of a language defect than something you actually want.
Ultimately, this is a property of the types and not the definitions.
As stated in C++ standard (8.5.11): If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an
object with automatic or dynamic storage duration has indeterminate value. [ Note: Objects with static or
thread storage duration are zero-initialized, see 3.6.2. — end note ]
This is exactly your case: a variable definition without explicit initializer.
So, let's see what default-initialized means (8.5.7):
To default-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9),
the default constructor for T is called
(and the initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, no initialization is performed.
This clearly states the difference between your two examples:
random_device is a class type, so its default constructor (the one without arguments) is implicitly called.
int is neither a class type nor an array type, so no initialization is performed, and it will have an indeterminate value until you explicitly initialize it (by assigning a value to it).

Initializiation confusion

Not sure of the appropriate title, but it stems from this discussion:
Do the parentheses after the type name make a difference with new?
On Visual Studio 2008, when I run the following code:
struct Stan
{
float man;
};
int main()
{
Stan *s1 = new Stan;
Stan *s2 = new Stan();
}
Examining the locals, s1 has an uninitialized float with a random value. s2 is value initialized to 0.
However, if I add a string data member, the float in both instances is uninitialized.
struct Stan
{
std::string str;
float man;
};
However, the string in both instances is initialized. I tried adding other non-POD classes instead of a string, but the latter case only occurs if I add a string data member. I gather that adding a string still keeps it a POD class? If it wasn't a POD class, then it should have value initialized regardless of the parenthesis, right? Any ideas why floats(and other primitive data types for that matter) aren't initialized when I add a string data member?
Adding a string stops the struct from being a POD class because a POD class must be an aggregate class with no members of type non-POD-struct and std::string has (amongst other things) user-declared constructors which makes it a non-POD-struct.
This is a known bug/feature of Visual Studio 2008. It doesn't support C++03 value initialization for non-POD types such as the structure in your second example.
With the struct as in your second example what should happen is the float is not initialized by new Stan but is zero initialized in new Stan().
Types with a user declared default constructor are initialized by calling that constructor in all cases, this happens correctly.
See here and here.
The behavior that you observe is a conforming behavior from the point of view of C++98 specification of the language.
The type in your first example is a so-called POD (Plain Old Data) type. When you apply the () initializer to a POD class type it performs zero-initialization of all data members of the class.
The type in your second example is not a POD type (because of the non-POD member str). When you apply the () initializer to a non-POD class type, it simply calls the class constructor to perform initialization. In your case the implicit [compiler-provided] constructor will properly initialize the str member, but will not do anything for the man member, which is why you see garbage in it.
Again, this is the correct behavior in C++98. It was changed in C++03. In C++03 the () initializer will perform value-initialization. In accordance with the rules of value-initialization, in your second example, the man field should also get zero-initialized in response to () initializer.
See also https://stackoverflow.com/questions/1976185/what-is-the-difference-between-new-myclass-vs-new-myclass for more detailed explanation .