es483
es483

Reputation: 361

Use of goto in this very specific case... alternatives?

I have a question about the possibile use of goto in a C++ code: I know that goto shall be avoided as much as possibile, but in this very particular case I'm having few difficulties to find good alternatives that avoid using multiple nested if-else and/or additional binary flags... The code is like the following one (only the relevant parts are reported):

// ... do initializations, variable declarations, etc...

    while(some_flag) {
        some_flag=false;

        if(some_other_condition) {
            // ... do few operations (20 lines of code)

            return_flag=foo(input_args); // Function that can find an error, returning false
            if(!return_flag) {
                // Print error
                break; // jump out of the main while loop
            }

            // ... do other more complex operations
        }

        index=0;
        while(index<=SOME_VALUE) {
            // ... do few operations (about 10 lines of code)
            return_flag=foo(input_args); // Function that can find an error, returning false
            if(!return_flag) {
                goto end_here; // <- 'goto' statement
            }

            // ... do other more complex operations (including some if-else and the possibility to set some_flag to true or leave it to false
            // ... get a "value" to be compared with a saved one in order to decide whether to continue looping or not
            if(value<savedValue) {
                // Do other operations (about 20 lines of code)
                some_flag=true;
            }
            // ... handle 'index'
            it++; // Increse number of iterations
        }

        // ... when going out from the while loop, some other operations must be done, at the moment no matter the value of some_flag

        return_flag=foo(input_args);
        if(!return_flag) {
            goto end_here; // <- 'goto' statement
        }

        // ... other operations here
        // ... get a "value" to be compared with a saved one in order to decide whether to continue looping or not
        if(value<savedValue) {
            // Do other operations (about 20 lines of code)
            some_flag=true;
        }

        // Additional termination constraint
        if(it>MAX_ITERATIONS) {
            some_flag=false;
        }

        end_here:
        // The code after end_here checks for some_flag, and executes some operations that must always be done,
        // no matter if we arrive here due to 'goto' or due to normal execution.
    }
}

// ...

Every time foo() returns false, no more operations should be executed, and the code should execute the final operations as soon as possible. Another requirement is that this code, mainly the part inside the while(index<=SOME_VALUE) shall run as fast as possible to try to have a good overall performance.

Is using a 'try/catch' block, with the try{} including lots of code inside (while, actually, the function foo() can generate errors only when called, that is in two distinct points of the code only) a possibile alternative? Is is better in this case to use different 'try/catch' blocks? Are there other better alternatives?

Thanks a lot in advance!

Upvotes: 0

Views: 289

Answers (3)

bipll
bipll

Reputation: 11940

It's C++! Use exceptions for non-local jumps:

try {
    if(some_result() < threshold) throw false;
}
catch(bool) {
    handleErrors();
}
// Here follows mandatory cleanup for both sucsesses and failures

Upvotes: 1

Three obvious choices:

  1. Stick with goto

  2. Associate the cleanup code with the destructor of some RAII class. (You can probably write it as the delete for a std::unique_ptr as a lambda.)

  3. Rename your function as foo_internal, and change it to just return. Then write the cleanup in a new foo function which calls foo_internal

So:

return_t foo(Args...) {
    const auto result = foo_internal(Args..);
    // cleanup
    return result;
}

In general, your function looks too long, and needs decomposing into smaller bits.

Upvotes: 1

user9212993
user9212993

Reputation:

One way you can do it is to use another dummy loop and break like so

 int state = FAIL_STATE;

 do {
     if(!operation()) {
         break;
     }

     if(!other_operation()) {
         break;
     }
     // ...
     state = OK_STATE;
 } while(false);

 // check for state here and do necessary cleanups

That way you can avoid deep nesting levels in your code beforehand.

Upvotes: 1

Related Questions