10

Could somebody indicate which clause in the Standard supports the following behavior obtained in Coliru, for the snippet:

#include <iostream>

class A
{
    int i;
    float x;

    public:
    A() : i(10) {}
    A(int i) : i(i) {}
    int GetI() { return i; }
    float GetF() { return x; }
};


int main()
{
    A a;
    A b(1);
    A x{};
    A y{1};
    std::cout << a.GetI() << '\n';
    std::cout << a.GetF() << '\n';
    std::cout << b.GetI() << '\n';
    std::cout << b.GetF() << '\n';
    std::cout << x.GetI() << '\n';
    std::cout << x.GetF() << '\n';
    std::cout << y.GetI() << '\n';
    std::cout << y.GetF() << '\n';
}

The code prints:

10
0 <-- Shouldn't be unknown?
1
0 <-- idem
10
0
1
0

Edit:

This paragraph was obtained from the TCPL 4th edition, page 490:

For this, the rules are not as clean as we might like. For statically allocated objects (§6.4.2), the rules are exactly as if you had used {}, so the value of alpha is {"","",0}. However, for local variables and free-store objects, the default initialization is done only for members of class type, and members of built-in type are left uninitialized, so the value of beta is {"","",unknown}.

Mr. Stroustrup doesn't say anything about undefined behavior.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
Wake up Brazil
  • 3,421
  • 12
  • 19
  • 5
    Reading an uninitialized variable is undefined behavior. Anything can happen, including (but not limited to) it evaluating to zero. – Mat Dec 24 '13 at 22:24
  • 1
    `Shouldn't be unknown?` What do you expect to be printed? – Andy Prowl Dec 24 '13 at 22:26
  • See [this](http://stackoverflow.com/a/6032889/2970947) answer. – Elliott Frisch Dec 24 '13 at 22:28
  • In the real world, the values of uninitialized variables just evaluating to zero in a newly started process is quite probable, as modern operating systems typically zero out memory pages before handing them out to applications for security reasons. – JohannesD Dec 24 '13 at 22:28
  • 0 is a perfectly valid unknown number, just as [4](https://xkcd.com/221/) is a perfectly valid random number. – Boann Dec 25 '13 at 04:37

4 Answers4

7

0 is one of the possible arbitrary value an uninitialized variable can acquire: the program has undefined behavior. Given that there is a fair chance that memory starts off zero initialized, 0 is a likely outcome: the IEEE 754 representation for 0 happens to be all zeros. There is, however, no guarantee that the value will be 0.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • It's not even random, though. It's just wrong. – tmyklebu Dec 24 '13 at 22:33
  • See my edit above about undefined behavior – Wake up Brazil Dec 24 '13 at 22:33
  • @WakeupBrazil: See the standard about undefined behaviour instead. – tmyklebu Dec 24 '13 at 22:35
  • @tmyklebu As I said above, I'd like to see where in the Standard does it say anything about this specific case. – Wake up Brazil Dec 24 '13 at 22:39
  • Do some implementations **always** initialize uninitialized automatic to 0 or is it always random (whatever is on the stack in the memory location chosen)? – Fiddling Bits Dec 24 '13 at 22:42
  • 1
    @WakeupBrazil: The relevant clause about reading uninitialized values is, I think, 4.1 [conv.lval] paragraph 1: "... If the object to which the glvalue refers is not an object of type T and is not an object of a type derived from T, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior. ...". – Dietmar Kühl Dec 24 '13 at 22:43
  • @FiddlingBits: Most UNIXes start off with zero initialized pages. I'm not aware of any implementation which initializes memory to zero. I heart that VC++ can be put into a mode where it fills uninitialized memory with a known pattern (`0xdeadbeef` or something like this) but I only heart about this second hand. – Dietmar Kühl Dec 24 '13 at 22:45
  • @DietmarKühl But there is no lvalue-to-rvalue conversion in the expression `A a;` – Wake up Brazil Dec 24 '13 at 22:48
  • 1
    @WakeupBrazil: I didn't claim there is. There is, however, an lvalue-to-rvalue conversion in `std::cout << a.getF();`: you get undefined behavior when you look at uninitialized data. – Dietmar Kühl Dec 24 '13 at 22:51
  • @DietmarKühl We actually use the cookie `0xDEADBEEF` in one of our products. It's in uinitialized RAM. If a power outage is short enough, the cookie survives, otherwise, it's lost and we know the power outage was not spurious. – Fiddling Bits Dec 24 '13 at 23:00
  • @DietmarKühl "Most UNIXes start off with zero initialized pages" I'm not familiar with UNIXes. Thus I was not expecting a 0 value in the stack. But after trying to print an unitialized `int` in the code above, I also got 0, although with a warning. I'm giving you the credit for the answer. Tks – Wake up Brazil Dec 24 '13 at 23:43
  • 1
    It would be more accurate to call it *arbitrary* rather than *random* (the latter word has a specific meaning). – Keith Thompson Dec 25 '13 at 01:34
  • @KeithThompson: I have changed the term in the answer. Thanks! – Dietmar Kühl Dec 25 '13 at 04:03
2

At Mat pointed out, reading an uninitialized variable in C++ in undefined behaviour, which means that anything can (and probably will, on some system) happen.

Depending on your compiler and its build configuration, you'll end up with a random value in x. In your case, it happens to be 0.0, but it can be any random value, depending on what data happened to occupy the piece of memory x happened to end up in.

In C++, it is generally considered very bad practise to not initialise member variables in the constructor, especially if you cannot guarantee that they will be initialised before they are being read.

Timo Geusch
  • 24,095
  • 5
  • 52
  • 70
1

What exactly do you expect "unknown" to mean? 0 is a perfectly reasonable value for an uninitialised variable with an unspecified value. It's just pure chance.

The important thing is that the float was not initialised, and in the passage you quote, BS doesn't talk about undefined behaviour because he's not referring to the syntax you're asking about, but instead about aggregate initialisation (and its variants).

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

It's worse than just arbitrary value. Even assuming that your compiler just uses the value left in memory and acts on the variable normally thereafter, the pre-existing bits could represent a floating-point trap value and end your program on first access.

But it goes even beyond that. Because the C++ Standard designates lvalue->rvalue conversion on uninitialized data as undefined behavior, the compiler is perfectly permitted to do anything it wants to your code, even the code that's unrelated to this variable, and even before the first access to this variable (as long as it can prove the undefined read of the variable is coming, which proof generally is easy only within the same basic block).

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720