On Nov 19, 3:39 am, Kira Yamato <kira...@earthlink.net> wrote:
On 2007-11-18 06:41:10 -0500, James Kanze <james.ka...@gmail.com> said:
switch ( something )
{
case 0 :
int a = 0 ; // Illegal...
break ;
case 1:
int b ; // Legal...
b = 0 ;
break ;
}
(How's that for adding to the confusion:-)?)
This is so weird. Is there a reason for initiations in switch
statements to be illegal?
It's the result of a more general rule: you're not allowed to
jump around a non-trivial initialization: either an explicit
initialization or a definition with a type which has a
non-trivial constructor. Thus, for example, something like:
goto foo ;
std::ifstream in( "filename" ) ;
foo:
int i ;
in >> i ;
is illegal. In this case, it's also quite obvious that it
should be: you're attempting to use "in" without having invoked
its constructor, which can only cause problems. And of course:
goto foo ;
int i = 43 ;
foo :
std::cout << i ;
suffers from the same problem; you're attempting to use an
uninitialized i.
The apparently strange behavior in my example with switch is due
to this rule interacting with other particularities of the
language: the fact that the semantics of switch are exactly
those of goto, for example (think of what happens if you leave
out a break), and the fact that something like:
switch ( something ) {
int a ;
case 0 :
a = 1 ;
// ...
break ;
case 2:
a = 2 ;
// ...
break ;
}
is legal C, and the authors probably didn't want to break it in
C++.
The final result is that in almost every case, you should wrap
the actions in each case in {...}.
However, I noticed that if you put braces around the case
blocks, then it compiles fine under g++ 4.0.1.
Yes, because you don't jump around the initialization; the
variable isn't visible in the other cases.
Some other weird observations below.
The following is legal (under g++ 4.0.1).
switch(something)
{
case 0:
int a; // ok
a = 1;
break;
case 1:
int b = 1; // ok too!
break;
}
Correct. What makes the code illegal is the presence of a case
after the the definition.
The following is illegal.
switch(something)
{
case 0:
int a; // ok
a = 1;
break;
case 1:
int b = 1; // illegal here!
break;
case 2:
int c; // ok
c = 1;
break;
}
The following is legal.
switch(something)
{
case 0:
int a; // ok
a = 1;
break;
case 1:
int b; // ok
break;
case 2:
int c = 1; // ok
c = 1;
break;
}
It seems like the rule is that you cannot initialize a
variable in a declaration in a case block that is followed by
another case block.
That's the general idea. To put it more exactly, there is no
such thing as a "case block", and case labels are considered as
a target of a goto. The "block" is thus that of the switch, and
the rule is that you're not allowed a goto over a definition
with a non-trivial initialization to a point where the variable
being defined is still legal.
In practice, in all but the most trivial cases (every case
consists of just a single assignment or return), you should
probably systematically wrap all cases in a block, e.g.:
switch ( something )
{
case 0 :
{
// ...
}
break ;
case 1 :
{
// ...
}
break ;
}
etc.
Thanks for the detail explanation.