Objects initialized by default

As far as I know, static or const objects are initialized by default. Is it true? And is there any other type of object which is by default initialized?
PS: I don't think primitive type are initialized by default.
Last edited on
Last edited on
The links' content is confusing but the examples are clearer. From the first link I got that, built-in types (types with no default ctor) are not initialized by default whether they're variables, const or even static, if there're inside a function.
For instance:

1
2
3
4
5
6
7
8
9
int f(bool b)
{
    int x;               // OK: the value of x is indeterminate
    int y = x;           // undefined behavior
    unsigned char c;     // OK: the value of c is indeterminate
    unsigned char d = c; // OK: the value of d is indeterminate
    int e = d;           // undefined behavior
    return b ? d : 0;    // undefined behavior if b is true
}


1
2
3
int n; // static non-class, a two-phase initialization is done:
       // 1) zero initialization initializes n to zero
       // 2) default initialization does nothing, leaving n being zero 


But n above as a global variable and mem as a class data member (in both structs below) are all initialized to zero:
1
2
3
4
5
6
7
struct T1 { int mem; };
 
struct T2
{
    int mem;
    T2() { } // "mem" is not in the initializer list
};


But in the second link I got:
1
2
3
T () ;
T t = {} ;                      // (2)
T {} ; (since C++11)

Zero-initialization is performed in the following situations:
2) As part of value-initialization sequence for non-class types and for members of value-initialized class types that have no constructors, including value initialization of elements of aggregates for which no initializers are provided.

The effects of zero-initialization are:
If T is a scalar type, the object is initialized to the value obtained by explicitly converting the integer literal ​0​ (zero) to T.

So in this case some expression like int i; should always be default initialized since int is of type scalar.

I'm still rather confused which comprehension from either of the links is right!
Last edited on
IMO, one of the things that makes C++ tricky to learn well is the variety of ways to do things, with a bunch of rules. In cppreference there is a whole section on initialisation, with like 9 ways of doing it:

https://en.cppreference.com/w/cpp/language/initialization

One should read the detail on all of them.

The rules are all there for a reason, they makes sense, but I guess they could be seen as being confusing if taken in isolation.

There is a school of thought that: instead of worrying about every detail of whether something is automatically initialised for you, just explicitly initialise each variable once you have a sensible value.

frek wrote:
So in this case some expression like int i; should always be default initialized since int is of type scalar.


In the particular case where zero initialisation is happening, yes. But not for every expression of int i; For example variable x in your first example has an indeterminate value.

frek wrote:

I'm still rather confused which comprehension from either of the links is right!


It's not which is right, all of them are :+)
Any reference on initialization is quite a battle between correctness and readibility. Both "static" and "const" mean different things in different contexts, and so does "by default initialized".

To stick to objects of "built-in types" without initializers, that are not subobjects or array elements, and the role of const and static, which I think you're mainly asking about,
1
2
3
4
5
6
7
8
9
10
11
int gn;                // initialized to 0
static int gsn;        // initialized to 0
const int gcn;         // compile-time error
static const int gscn; // compile-time error
int main()
{ 
  int ln;                // contains garbage
  static int lsn;        // initialized to 0
  const int lcn;         // compile-time error
  static const int lscn; // compile-time error
}
live demo to show the errors: https://wandbox.org/permlink/cj6ILQpJ9jrQ7jMC

If you add {} or () or =0 after any of those, they will all initialize to zero (as in const int lcn{}; or const int lcn(); (oh right, forgot about MVP) or const int lcn = 0; will all do the same thing)
Last edited on
static variables are initialised if no initial value is provided.


Static initialization

There are two forms of static initialization:
1) If possible, constant initialization is applied.
2) Otherwise, non-local static and thread-local variables are zero-initialized.

In practice:

Constant initialization is usually applied at compile time. Pre-calculated object representations are stored as part of the program image. If the compiler doesn't do that, it must still guarantee that the initialization happens before any dynamic initialization.
Variables to be zero-initialized are placed in the .bss segment of the program image, which occupies no space on disk and is zeroed out by the OS when loading the program.


const objects are not. They need to be initialised (even if just using {} ).
I guess you all think that data members of the class below are default initialized:
1
2
3
4
5
6
7
8
9
10
struct T {
    float f;
    int gn;
    char ch;
};

int main() {
    T t;
    std::cout << t.gn << ' ' << t.f << ' ' << int(t.ch);
}

But the int variable contains garbage data! Test it.
If we change line 8 to T t(); we will get a couple of errors on Coliru, for example! https://coliru.stacked-crooked.com/a/feebe286c42dd74d
But T t{}; works.

So I think there are only two ways to assure us about the built-in types to be default initialized:
Initialized them, or use empty curly braces.
If you disagree, please tell me.
Last edited on
T t();
doesn’t do what you appear to think it does.

Go look “most vexing parse”.
Honestly, my worthless 2 cents... objects should be fine without anything at all, as their ctor and internal variable initializations should take care of it. Only simple types like int should need an init unless you have a value in mind.
> data members of the class below are default initialized

Yes.


> But the int variable contains garbage data! Test it.

Yes, default initialisation of an object of type int does nothing.

otherwise, no initialization is performed: the objects with automatic storage duration (and their subobjects) contain indeterminate values.
https://en.cppreference.com/w/cpp/language/default_initialization



> there are only two ways to assure us about the built-in types to be default initialized:
> Initialized them, or use empty curly braces.

If we explicitly initialise them or use an empty pair of curly braces,
the initialisation would not be default initialisation.

Default initialisation is
the initialization performed when an object is constructed with no initializer.
https://en.cppreference.com/w/cpp/language/default_initialization


Note that default initialisation of an object of type int would result in an object with an indeterminate value;
an attempt to use this indeterminate value would engender undefined behaviour.
I mentioned T(); because on cppreference it's been put next to T{}; with the same category number (2) with this explanation: https://en.cppreference.com/w/cpp/language/zero_initialization#Explanation

@JLBorges
I got your points, they're right. But I'm still not able to wrap things up. Could you write what you've gathered, for example, on a conclusion list, regarding built-in types default initialization so that they can be used in various situations without undefined behaviour.
No, @frek, you didn't.

There is a very big difference between
T t();
which I alluded to, and
T();
which you have just mentioned.

The first tries (unsuccessfully) to declare a function called t that returns an entity of type T. (It would compile - albeit not do what you presumably intended - if you declared it outside of any other function, including main()). The second (successfully if there is one) invokes a constructor of T with no parameters.

The following will invoke compiler warnings, but not errors. It will produce garbage, obviously, but will run.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

struct T {
    float f;
    int gn;
    char ch;
};

T t();        // <==== Move it here. Note the (). This is the declaration of a function, NOT a variable of type T
    
int main() {
    T t;      // <==== Unfortunate use of the same name, but not an error. Note: no (). This is a variable of type T.
    std::cout << t.gn << ' ' << t.f << ' ' << int(t.ch);   // garbage, obviously, but a separate issue
}





frek wrote:
So I think there are only two ways to assure us about the built-in types to be default initialized:
Initialized them, or use empty curly braces.
If you disagree, please tell me.

I disagree.

"default initialized" means that they would be initialised without any action on your part.

If you initialise them by explicitly stating a value then clearly you aren't default-initialising!

If you use empty curly braces then you ... are initialising them with a type equivalent of a zero. "Uniform initialisation" or "brace initialisation" or "initialising to a default value", not "default initialisation". You are assigning a value, even if you don't state that value explicitly.
Last edited on
Could you write what you've gathered, for example, on a conclusion list, regarding built-in types default initialization so that they can be used in various situations without undefined behaviour.


It's already been said:

If you add {} or () or =0 after any of those, they will all initialize to zero (as in const int lcn{}; or const int lcn = 0; will all do the same thing)

> there are only two ways to assure us about the built-in types to be default initialized:
> Initialized them, or use empty curly braces.

As I said earlier, just initialise everything, It's been a golden rule in programming from the very beginning. Don't forget to validate all the data as well.

The rules that will allow the compiler to initialise for you, are a small convenience IMO, as long as one can remember the rules. If one is having trouble with that, then initialise yourself.

The compiler should be able to warn about possible use of uninitialised values.
Topic archived. No new replies allowed.