Search code examples
c++initialization

C++ default value initialization changes with input-output streams


I am researching an interesting behavior for two code segments, that give me unexpected behavior.

Describing The behavior

Code segment 1:

#include <iostream>

using namespace std;

int main()
{
    long long n;
    long long m;
    
    // cin >> n;

    cout << m;

    return 0;
}

When I run this (for example in https://www.onlinegdb.com/online_c++_compiler), the value printed in the console (the value inside the variable m) is 0. This is expected and corresponds to the fact that the long long type has a default initialization to 0 (zero initialization).

Code segment 2:

#include <iostream>

using namespace std;

int main()
{
    long long n;
    long long m;
    
    cin >> n;

    cout << m;

    return 0;
}

By uncommenting the line with cin and adding any value, I do not get 0, but rather a different value depending on the number I input for n. Other characteristics of this behavior are:

  1. For different input values for n, we get different values in m.
  2. Each time the same value is given for n, we get the same value in m.
  3. Defining n or m static results in the expected behavior, which is m carrying the value 0.
  4. The same behavior persists if m, n are ints

The unexpected behavior is thus that m does not have a default initialization to 0.

Discussion

My explanation

  1. The uncommented line, cin >> n, creates a new thread for execution.
  2. The new thread creates a new stack to which all local variables are copied.
  3. Since m is not initialized in the original stack, the value it carries is indeterminate in the new stack. It depends on the state of the current stack. But the state of the stack is dependent on the state of the original copied stack, which, in turn, is dependent on the value of the input n.

Issues

My explanation is congruent with characteristic 3. Nevertheless, I do not know how to check for this using a single thread. Moreover, the reason might be something more than stack-related such that even with one and only one thread, the behavior persists. What do you think?


Solution

  • C++ initialization is super complicated. However, this case is rather simple (confusing terminology aside ;). You are right that both m and n are default initialized. Though, immediately after that your interpretation is rather off. It starts with

    This is expected and corresponds to the fact that the long long type has a default initialization to 0 (zero initialization).

    Default initialization for long long int is not zero initialization. Actually it is no initialization at all. From cppreference:

    Default initialization is performed in three situations:

    1. when a variable with automatic, static, or thread-local storage duration is declared with no initializer;

    [...]

    and

    The effects of default initialization are:

    • if T is a non-POD (until C++11) class type, [... long long is not a class type ...]
    • if T is an array type, [... long longis not an array type ...]
    • otherwise, no initialization is performed: the objects with automatic storage duration (and their subobjects) contain indeterminate values.

    Reading an indeterminate value is undefined behavior. Adding or removing seemingly unrelated lines of code changing the output is typical effect of undefined behavior. The output of your code could be anything. It is undefined.