Home > OS >  Is there a reason to use zero-initialization instead of simply not defining a variable when it is go
Is there a reason to use zero-initialization instead of simply not defining a variable when it is go

Time:05-21

I came across a code example learncpp.com where they zero-initialized a variable, then defined it with std::cin:

#include <iostream>  // for std::cout and std::cin

int main()
{
    std::cout << "Enter a number: "; // ask user for a number

    int x{ }; // define variable x to hold user input (and zero-initialize it)
    std::cin >> x; // get number from keyboard and store it in variable x

    std::cout << "You entered " << x << '\n';
    return 0;
}

Is there any reason that on line 7 you wouldn't just not initialize x? It seems zero-initializing the variable is a waste of time because it's assigned a new value on the next line.

CodePudding user response:

Is there any reason that on line 7 you wouldn't just not initialize x?

In general, it is advised that local/block scope built in types should always be initialized. This is to prevent potential uses of uninitialized built in types which have indeterminate value and will lead to undefined behavior.

In your particular example though since in the immediate next line we have std::cin >> x; so it is safe to omit the zero initialization in the previous line.

Note also that in your example if reading input failed for some reason then prior to C 11, x still has indeterminate value but from C 11(&onwards) x will no longer has indeterminate value according to the below quoted statement.

From basic_istream's documentation:

If extraction fails (e.g. if a letter was entered where a digit is expected), zero is written to value and failbit is set. For signed integers, if extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max() or std::numeric_limits<T>::min() (respectively) is written and failbit flag is set. For unsigned integers, if extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max() is written and failbit flag is set.

It seems zero-initializing the variable is a waste of time because it's redefined on the next line.

As i said, in your example and assuming you're using C 11(& higher), you can safely leave off the zero-initialization.


then defined it with std::cin

No the use of std::cin does not "define" it(x). Definition happened only once when you wrote:

int x{ }; //this is a definition

Even if you leave the zero initialization, then also it will be a definition:

int x;  //this is also a definition but x is uninitialized here

CodePudding user response:

The problem you're encountering is, that in order to use the >> operator of std::cin, you have to have your variable declared beforehand, which is, well, undesirable. It also leads to your question of whether or not to initialize the variable.

Instead, you could do something like this:

#include <iostream>
#include <iterator>

int main()
{
    std::cout << "Enter a number: ";
    auto const i = *std::istream_iterator<int>(std::cin);
    std::cout << "You entered " << x << '\n';
}

... although that's also problematic, since you're at the end-of-file, then the behavior is undefined.

Now, you might be asking "why is this guys talking to me about alternatives to the common way of doing things, then telling me that the alternative isn't good enough either?"

The point of my doing this is to introduce you to an uncomfortable fact of "C life", which is: We are often stuck with design decisions of the standard library which are not optimal. Sometimes, there's really no better alternative; and sometimes there is, but it wasn't adopted - and since C does not easily change designs of standard library classes, we may be stuck with some "warts" in the language. See also the discussion in the related question I've opened:

Why do C istreams only allow formatted-reading into an existing variable?

  • Related