1

When I define an enum class inside a function, it has a value from the available options. However, when I define it within a class, it has value of none of the options. So what is the initial value of g.f? what will return true when compared? ((g.f==??)==true) ?

#include <iostream>

enum class Fruit
{
    apple,
    orange
};

class Garden
{
public:
    Fruit f;
};

void print_enum(Fruit f)
{
    switch(f)
    {
        case Fruit::apple:
            std::cout<<"apple\n";
            break;
        case Fruit::orange:
            std::cout<<"orange\n";
            break;
        default:
            std::cout<<"other\n";
            break;
    }   
}

int main()
{
    Garden g;
    Fruit f;

    print_enum(f); // apple
    print_enum(g.f); // other

    return 0;
}
ar2015
  • 5,558
  • 8
  • 53
  • 110
  • 6
    Undefined behaviour. There is no reliable initial value here, and printing it can cause other problems too. *You* have to assign a value. – deviantfan Jul 22 '17 at 06:22
  • @deviantfan, I know it is an undefined behavior. But why it is neither `apple` nor `orange`? – ar2015 Jul 22 '17 at 06:23
  • 5
    Because it's UB? Do you expect UB making sense? – deviantfan Jul 22 '17 at 06:23
  • 1
    Uninitialized local variables (like both `g` and `f`) have an *indeterminate* value. – Some programmer dude Jul 22 '17 at 06:25
  • Undefined behavior means it will not make sense by definition. It may be precisely defined for a given compiler, but will differ compiler to compiler. That is why UB is so dangerous. You're lucky it's giving you completely arbitrary values, to let you know it's UB. – Alex Huszagh Jul 22 '17 at 06:26
  • 2
    Regarding all the talk about *undefined behavior*, you might want to [read a bit more about it](http://en.cppreference.com/w/cpp/language/ub). – Some programmer dude Jul 22 '17 at 06:27
  • I mean, it's good that your compiler makes it being neither apple nor orange. This way, you are not mislead in thinking that it would be valid code. Happens that people continue using code that works because of a well-meaning compiler and then everything goes down when compiled elsewhere. – Aziuth Jul 22 '17 at 07:23

2 Answers2

1

Always initialize your variables, C++ doesn't intialize them with a "default" value in several occasions.

In both cases you have written here you are at the mercy of your compiler and OS, but likely you'll end up with garbage in your enum variable (that's what you experiment in your latter case). If you want to see what that garbage is, execute this:

std::cout << (int)g.f << std::endl;
Daniel
  • 21,933
  • 14
  • 72
  • 101
  • it is `-1875479328` – ar2015 Jul 22 '17 at 07:48
  • There it is, it's what one commonly calls `garbage` but it's actually the value of whatever was using that memory before your variable was using that space. Just remember to initialize your variables to `0`, `null`, `apple` or whatever makes sense in each case. – Daniel Jul 22 '17 at 20:24
1

The standard stipulates that accessing the value of an uninitialised variable of automatic storage duration gives undefined behaviour.

The consequence is that any operation which relies on accessing the value gives undefined behaviour. Accessing the value of a variable is necessary to;

  • Compare it with another value. For example, a == b gives undefined behaviour if either a or b is uninitialised. Even the comparison a == a gives undefined behaviour if a is uninitialised.
  • Assign the value to another variable. For example, a = b gives undefined behaviour if b is uninitialised.
  • Pass it to a function by value. For a function f(), the call f(a) will give undefined behaviour if a is uninitialised.
  • Output the value. For example, std::cout << a gives undefined behaviour if a is uninitialised.

Because of this, there is no point in requiring an uninitialised variable to have a particular value. Accessing the value gives undefined behaviour, so testing if it is equal (or not equal, or greater than, or ....) to any value gives undefined behaviour.

This is often summarised by describing the value of an uninitialised variable as indeterminate. If it is not possible to access a value without introducing undefined behaviour, it is not possible to reliably determine what the value is.

Of course, there is then the question of why the standard deems that accessing the value of an uninitialised variable gives undefined behaviour. Leaving the value uninitialised allows the compiler to allocate memory for the variable (e.g. from stack) but not bother initialising it - the data in that memory can be whatever happens to be there. Initialising a variable to any specified value can be an expensive operation (e.g. an array of two million elements is a variable, albeit a big one, and initialising it may be computationally expensive). It is also often an unnecessary operation, since the first thing a lot of code does to an initialised variable is (wait for it ....) to assign a value to it i.e. to initialise it.

An operation that is (potentially) both unnecessary and computationally wasteful tends to be unpopular with both programmers and compiler vendors. Making the behaviour undefined does away with all of that .... albeit by requiring programmers to be careful to initialise their variables before any operation that accesses their values.

Peter
  • 35,646
  • 4
  • 32
  • 74