> Normally variables have a clear scope: they are constructed when you declare them,
> they are destroyed when they go out of scope.
Normally Always variables have a clear scope: they are constructed when you
declare define them, they are destroyed when they go out of scope (if they have an automatic storage duration).
Always. Presence of
goto does not change the object lifetime and scoping rules of the language.
> This is another hazard of goto. It confuses/breaks variable scope rules.
> ...
> But with goto you can jump in and out of a variable's scope leading to confusing ctor/dtor calls.
It is not a hazard of
goto. This is the hazard with programmers who are confused about scoping rules, about object lifetime and about initialization and deinitialization. They would remain confused programmers even if they decided never to use a
goto. For instance, they would have the same problems when they use a
switch-case construct -
case and
default are labels, with the
switch being an implicit
goto to the appropriate label.
Fortunately, compilers do not get confused about object lifetime, even when they encounter a
goto or a
switch-case. They detect silly scoping errors and won't pass the code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
#include <string>
void foo( int i )
{
label:
{
int j = i ;
i -= j ;
}
if( i > 10 ) goto label ; // fine
}
void bar( int i )
{
{
int j = i ;
label:
i -= j ;
}
if( i > 10 ) goto label ; // *** error: jump bypasses variable initialization
}
void baz( int i )
{
{
std::string a ;
label:
--i ;
}
if( i > 10 ) goto label ; // *** error: jump bypasses variable initialization
}
|
http://coliru.stacked-crooked.com/a/3b25ae271e9f785b
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
#include <iostream>
struct A
{
int v ;
A( int i ) : v(i) { std::cout << v << " A::constructor\n" ; }
~A() { std::cout << v << " A::destructor\n" ; }
};
void foobar( int i )
{
std::cout << "foobar(" << i << ")\n" ;
{
A a(1) ;
if( i > 5 ) goto label ;
A b(2) ;
if( i > 0 ) goto label ;
A c(3) ;
--i ;
}
label:
--i ;
std::cout << "..................\n" ;
}
int main()
{
foobar(22) ;
foobar(2) ;
foobar(-2) ;
}
|
http://coliru.stacked-crooked.com/a/470476e18d0410df
foobar(22)
1 A::constructor
1 A::destructor
..................
foobar(2)
1 A::constructor
2 A::constructor
2 A::destructor
1 A::destructor
..................
foobar(-2)
1 A::constructor
2 A::constructor
3 A::constructor
3 A::destructor
2 A::destructor
1 A::destructor
.................. |