Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Standard reference for int foo = foo

int foo = foo; compiles. Which part of the C++ standard allows this?

like image 889
Rohan Avatar asked May 31 '11 14:05

Rohan


People also ask

What is int foo in C?

int& foo(); is a function returning a reference to int . Your provided function returns int without reference. You may do int& foo() { static int i = 42; return i; } int main() { int& foo(); foo() = 42; } Follow this answer to receive notifications.

What is the Foo function in C++?

Foo (pronounced FOO) is a term used by programmers as a placeholder for a value that can change, depending on conditions or on information passed to the program.

How do you declare foo in C++?

In C++ int& foo() declares a function having a function named foo() of data type int&. The foo() function of type int& returns a reference to an int instead of a int value. Likewise, we can declare the foo() with other data types as well.


2 Answers

3.3.1 Point of declaration [basic.scope.pdecl]

The point of declaration for a name is immediately after its complete declarator (clause 8) and before its initializer (if any),

The behaviour is well defined if the declaration is at file scope. If you have the declaration at function scope and if you use foo later on [which would be initialized to some unspecified value in that case] the behaviour would be undefined.

like image 154
Prasoon Saurav Avatar answered Oct 19 '22 11:10

Prasoon Saurav


This?

int main() {
  int foo = foo;
}

The object foo does exist after the =, according to [basic.scope.pdecl]:

The point of declaration for a name is immediately after its complete declarator (clause 8) and before its initializer (if any).

However, the program as a whole is undefined, because you use (on the RHS) an uninitialised value:

int x = x; Here [..] x is initialized with its own (indeterminate) value.

And:

Though "inferred and ill-specified" by the standard, an lvalue-to-rvalue conversion is performed on the RHS expression foo.

And ([conv.lval]):

An lvalue (3.10) of a non-function, non-array type T can be converted to an rvalue. If T is an incomplete type, a program that necessitates this conversion is ill-formed. If the object to which the lvalue 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.

With proper warning levels, you will get told about it; however, programs invoking Undefined Behaviour are allowed to compile. They just can do anything at all when you run them.


Or, what about this?

int foo = foo;    
int main() {}

Notice that foo is a "global". These are zero-initialised as a first step, according to [basic.start.init]:

Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place.

So you'll get an int foo with value 0; it's valid, at this point, as per [basic.scope.pdecl] above, and as per [stmt.decl]:

The zero-initialization (8.5) of all local objects with static storage duration (3.7.1) is performed before any other initialization takes place. [..]

You then value-initialise it to foo (itself), i.e. 0.

This is well-defined... if a little cryptic.


In the interests of thoroughness, here's a third and final case:

int foo = 42;
int main() {
   int foo = foo;
}

Sadly, this is the same as the first case. Since the local foo is already declared and in scope by the time the initializer is evaluated, the initializer uses the local foo and you're still stuck with the Undefined Behaviour. The global foo is not used.

like image 33
Lightness Races in Orbit Avatar answered Oct 19 '22 13:10

Lightness Races in Orbit