C++ And goto Don't Match Together
As you can see by reading this blog, I'm a fan of goto when used in an appropriate way. Unfortunately it works for C only - not C++.
The issue is all in this short paragraph (6.7/3) of the C++ standard:
It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a local variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has POD type (3.9) and is declared without an initializer (8.5).
Jan 2012 Draft
This means that your C++ compiler will not build many C sources if you have used goto
s to bypass initializations.
The solution to maintain the same functionality and the same structure of your code is to use exceptions. I'm sure you are thinking "why cannot I simply use some nested ifs?" My answer is "readability over all!"
An Example
Let's see a quick example, as I would write it in C.
int foo()
{
int err = 0;
X *x = NULL;
Y *y = NULL;
x = x_factory();
if (x == NULL) {
err = 1;
goto clean_exit;
}
y = y_factory(x);
if (y == NULL) {
err = 2;
goto clean_exit;
}
while ( /* condition */ ) {
while ( /* other condition */ ) {
/* some code */
if ( /* critical error */ ) {
err = 3;
goto clean_exit;
}
}
}
/* some other code */
clean_exit:
if (x != NULL)
x_free(x);
if (y != NULL)
y_free(y);
return err;
}
The same code in C++ won't work, if in the code inside or after the loops there is some initialization. So, let's see how you would be tempted to rewrite it.
int foo()
{
int err = 0;
X *x = NULL;
Y *y = NULL;
x = x_factory();
if (x != NULL) {
y = y_factory(x);
if (y != NULL){
while ( /* condition */ ) {
while ( /* other condition */ ) {
/* some code */
if ( /* critical error */ ) {
err = 3;
break;
}
}
if (err != 0)
break;
}
if (err != 0) {
/* some other code */
}
} else {
err = 2;
}
} else {
err = 1;
}
if (x != NULL)
x_free(x);
if (y != NULL)
y_free(y);
return err;
}
Too many else
s and too indented, in my opinion. Below there is my version, using one of the most powerful constructs of C++: exceptions.
int foo()
{
int err = 0;
X *x = NULL;
Y *y = NULL;
try {
x = x_factory();
if (x == NULL)
throw(1);
y = y_factory(x);
if (y == NULL)
throw(2);
while ( /* condition */ ) {
while ( /* other condition */ ) {
/* some code */
if ( /* critical error */ )
throw (3);
}
}
/* some other code */
} catch (int exception_code) {
err = exception_code;
}
if (x != NULL)
x_free(x);
if (y != NULL)
y_free(y);
return err;
}
This is my opinion; what's your?