Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is 'int i = i;' legal? [duplicate]

Tags:

c++

Possible Duplicate:
int var = 1; void main() { int i = i; }

The following code can pass compiling under both g++ and Visual C++. Why is it legal? It looks unreasonable, and may cause hidden bugs.

int main() {
  int i = i;
}
like image 366
Aerodonkey Avatar asked Jun 25 '12 09:06

Aerodonkey


4 Answers

EDIT: It's syntactically legal, but results in undefined behavior if you use x.

It's not legal because you're assigning an uninitialized variable with another (well, the same) uninitialized variable. Just because it compiles doesn't mean it's legal. It's valid C++ syntax, yes, but not legal.

The right hand side of the assignment operator must be fully evaluated at the time of the assignment. In this case, that's i, which isn't initialized.

Credits to Steve Jessop, who dug up the quote:

4.1/1, lvalue-to-rvalue conversion

[...] if the object is uninitialized, a program that necessitates this conversion has undefined behavior.

like image 111
Luchian Grigore Avatar answered Oct 19 '22 16:10

Luchian Grigore


The reason it's allowed by the syntax is that there are some odd cases where you might conceivably want to use a variable by pointer or reference in its own initializer:

struct ThingManager {
    void *thing;
    ThingManager(void *thing) : thing(thing) {}
    void Speak() {
        if (thing == (void*)this) {
            std::cout << "I'm managing myself\n";
        } else {
            std::cout << "I'm managing " << thing << "\n";
        }
    }
};

ThingManager self_manager(&self_manager);
ThingManager other_manager(&self_manager);

So C++ lets you refer to an object in its own initializer expression (its name is in scope). Then as ever in C++, it's your problem to make sure you don't actually use an uninitialized value (your example, int i = i; does use an uninitialized value).

You compiler might help with identifying uses of uninitialized values, but the standard doesn't require it to.

like image 34
Steve Jessop Avatar answered Oct 19 '22 15:10

Steve Jessop


You can let g++ warn you about this use case with -Winit-self (in conjunction with -Wuninitialized), and if you treat warnings as errors, it should satisfy your itch.

This technique of using the copy constructor to self-initialize is sometimes used to suppress a global object's default constructor/initializer from executing. This may be necessary if the global object's default constructor is just to 0 initialize the object, but the object got used before the constructor would have been executed. As a throwback to C, globals are 0 initialized at program start, and then the C++ runtime begins to execute global constructors. For those narrow cases where the defined constructor that would have executed is only to 0 out the object, the self initialization does not do any harm.

In the general case, copy constructor self-initialization is bad practice, since it generally would cause the same sorts of problems that using an uninitialized variable would cause (that is, undefined behavior). In the particular example in the OP's question, i is local to main, and is therefore uninitialized. The result of reading an uninitialized variable is always undefined behavior.

like image 8
jxh Avatar answered Oct 19 '22 15:10

jxh


You can use any previously declared variable as an initialiser of another variable.

In this case as soon as the compiler parses int i it adds that to the symbol table, so when it sees the = i initialiser, the symbol can be resolved from the preceding declaration.

It is not an error because the compiler can make sense of it in that it can generate code that unambiguously does exactly what the source code specifies, even if it is semantically suspect. The philosophy of C and C++ is to compile anything that can possibly be compiled syntactically. Semantic errors generally issue only warnings, and only then if such warnings are enabled.

like image 3
Clifford Avatar answered Oct 19 '22 16:10

Clifford