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