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 gotos 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 elses 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?

Luca Sommacal

Luca Sommacal

Italian developer (mainly in C for embedded platforms), Linux learner, addicted to rock music, history, science and few other things. Follow me on Twitter

comments powered by Disqus