Nate DeSimone wrote:
In general gotos are *REALLY* bad
True, gotos have been 'out-of-style' for the last 10-15 years, and indeed, overly-liberal use of gotos is *REALLY* bad; however, I would claim that blind avoidance of goto's is just as bad.
I've seen people use all kinds of things to avoid typing 'goto' because they are '*REALLY* bad', including:
do { status = NtXXX(); if ( ! NT_SUCCESS(Status) ) break;
...
} while(0)
Or similar, but equivilant for or while loops; writing break when you mean goto doesn't make the code any better.
Similarly, the code could be written as:
try { status = NtXXX(); if ( ! NT_SUCCESS(Status) ) ExRaiseStatus(Status); } except(...) { // Do cleanup }
But this is just an expensive way of writing goto.
Sometimes, if you mean goto, it is just better to write goto.
On alternative to goto's for the the code in question might be:
status = NtXXX(); // Work A if ( NT_SUCCESS(status) ) { ... do some work B... ... if work fails, set status ... }
if ( NT_SUCCESS(status) ) { ... do some more work (C) that depends on A and B ... if work fails, make sure status is set ... }
if ( NT_SUCCESS(status) ) { ... do some more work (D) that depends on A, B and C ... if work fails, make sure status is set ... }
// If A was done, cleanup A // If B was done, cleanup B
if ( ! NT_SUCCESS(status) ) { ... Cleanup C and D in the failure case return status; }
// In success case, C and D are outputs in some way, so don't // clean them up return STATUS_SUCCESS.
Note that indentation from error checking never exceeds one level.
You do have to be able to figure out what work was done and what work wasn't, but the same would be true if all the NtXXX functions threw exceptions instead, unless you caught the exception from each function seperately, in which case, you'd get some pretty horrendous code. (Exceptions are not a panacea.)
Probably this isn't much, if any, better than the goto solution-- but it doesn't have the for letter word in it.
It might be possible to design a clean system using C++ object encapsulation of work, so that work is undone automatically during stack unwind... but that doesn't really apply here.
Thanks,
Joseph