When we make an open/close mechanism for a resource that uses subresources, we have 2 patterns to handle the subresources release in case of error:
1
RESULT Open() {
RESULT result;
result = OpenSubResourceA();
if (result == SUCCESS)
result = OpenSubResourceB();
/* Do not handle error case, the convention is that the caller
* will call Close whatever the return code of Open is */
return result;
}
2
RESULT Open() {
RESULT result;
result = OpenSubResourceA();
if (result == SUCCESS)
result = OpenSubResourceB();
if (result != SUCCESS)
ReleaseSubResourceA();
/* Release A if opening B failed since the convention is
* that the caller calls Close only if Open succeeds */
return result;
}
Of course we can generalize with more than 2 subresources.
What’s your favorite way of doing things ? And why ?
EDIT
Thanks for your inputs. The idea that the main resource shouldn’t be in some intermediate state outside of the Open/Close calls convinced me that #2 is indeed the best solution.
If operation fails, the resource should be in the same state as before the call, so the client can continue using it. It is bad practice to leave resource in indeterminate half-ready state, if some operation has failed. If you can not (do not want to) cleanup and recover from indeterminate state, then resource should be explicitly rendered into error state, e.g. some member like
isError()should start returningtrueThat is #2