Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper replacement for the missing 'finally' in C++

Since there is no finally in C++ you have to use the RAII design pattern instead, if you want your code to be exception safe. One way to do this is by using the destructor of a local class like this:

void foo() {
    struct Finally {
        ~Finally() { /* cleanup code */ }
    } finalizer();
    // ...code that might throw an exception...
}

This is a big advantage over the straight forward solution, because you don't have to write the cleanup code 2 times:

try {
    // ...code that might throw an exception...
    // cleanup code (no exception)
} catch (...) {
    // cleanup code (exception)
    throw;
}

A big disadvantage of the local class solution is that you can't directly access local variables in your cleanup code. So it will bloat your code a lot if you need access to them regardless:

void foo() {
    Task* task;
    while (task = nextTask()) {
        task->status = running;
        struct Finally {
            Task* task;
            Finally(Task* task) : task(task) {}
            ~Finally() { task->status = idle; }
        } finalizer(task);
        // ...code that might throw an exception...
    }
}

So my question is: Is there a solution which combines both advantages? So that you a) don't have to write duplicate code and b) can access local variables in the cleanup code, like task in the last example, but without such code bloat.

like image 237
Sascha Avatar asked Nov 20 '08 11:11

Sascha


1 Answers

Instead of defining struct Finally, you could extract your cleanup code in a function of the class Task and use Loki's ScopeGuard.

ScopeGuard guard = MakeGuard(&Task::cleanup, task);

See also this DrDobb's article and this other article for more about ScopeGuards.

like image 181
Sébastien RoccaSerra Avatar answered Nov 11 '22 16:11

Sébastien RoccaSerra