views:

241

answers:

2

Hi,

After tring my hand at perl and a little bit of C, I am tring to learn C++ and already i am bogged down by the details and pitfalls. Consider this:-

int x = 1;
{ 
  int x = x; // garbage value of x
}
int const arr = 3;
{ 
  int arr[arr]; // i am told this is perfectly valid and declares an array of 3 ints !! 
}

Huh, Why the difference ?

To Clarify: Use of the same name is valid in one case and invalid in another.

Thanks,

+13  A: 

Welcome to the universe of C++! For your question, the answer lay in a concept called 'Point-of-declaration'.

>>int x = 1;
>>{ int x = x; }  // garbage value of x

From Section:-3.3.1.1 (C++ Standard Draft) The point of declaration for a name is immediately after its complete declarator and before its initializer (if any), except as noted below.

int x = 12;
{ int x = x; }

Here; the 'operator =' is the initializer. You can say that the point-of-declaration for 'x' is not yet reached, so the value of 'x' is indeterminate.

>>int const arr = 3;
>>{ int arr[arr]; } // i am told this is perfectly valid and declares an array of 3 ints !!

Why? From Section:-3.3.1.4 (C++ Standard Draft) A nonlocal name remains visible up to the point of declaration of the local name that hides it. Here the point of declaration is reached at ';' character. So the earlier visible value of 'arr' is used i.e. = 3.

Also, you may wish to know that the following is valid :-

const int e = 2;
{ enum { e = e }; } // enum e = 2

From Section:-Chapter-3.3.1.4 (C++ Standard Draft):- The point of declaration for an enumerator is immediately after its enumerator-definition.

But, don't do this

const int Spades = 1, Clubs = 2, Hearts = 3, Diamonds = 4;
enum Suits
{
  Spades = Spades,     // error
  Clubs,               // error
  Hearts,              // error
  Diamonds             // error
};

Why? Because enumerators are exported to the enclosing scope of the enumeration. In the above example, the enumerators Spades, Clubs, Hearts, and Diamonds are declared. Because the enumerators are exported to the enclosing scope, they are considered to have global scope. The identifiers in the example are already defined in global scope. So its an error.

For additional details and pitfalls ( :-) ), read-up on section 3.3 'Declarative regions and scopes' from the Draft C++ Standard, if interested you can get hold of the pdf from here(http://www.research.att.com/~bs/SC22-N-4411.pdf).

Abhay
Thanks for the explanation, but why does it need to be so complex?
I think "You can say that the point-of-declaration for 'x' is not yet reached, so the value of 'x' is indeterminate" is wrong. The point of declaration is already reached, and this is the reason why 'x' is indeterminate, because it is already declared, but not yet initialised.
Gorpik
The reason the rules need to be complex is that C++ declarators *are* complex. There's a lot of capability in there, combined with a lot of backwards compatibility cruft, no clean break from its C history (where this stuff was not specified quite as formally and edge cases like this were often up to the compiler implementer), and you get the C++ standard rules.
Greg Hewgill
@Gorpik: I thought the same abt it until i read 'except as noted below'. The example is straight from the standard. I believe it means the point of declaration is not reached. Maybe Neil, litb etc can clarify.
Abhay
Daniel Earwicker
@Earwicker: Thanks for the suggestion. I will have a name in a few more months i think, after fall semester ...
+7  A: 

First, in real world you should use neither because it is confusing, and even a few seconds for understanding this fine point is too much waste.

Scrap the rest of my answer - Abhay already got it right, and in far more detail :)

MaxVT
While not a real answer to the question, it gets an upvote for pragmatism.
Joel Goodwin
+1 I agree with your pragmatism too :-). But i guess the O.P. as a learner was taken by surprise with the nature of pitfall.
Abhay
+1 Just don't ever put such code into production systems.
sharptooth