M
mike3
Hi.
I've got some stuff that looks like this:
---
ErrorCode MyFunc()
{
BigNum a, b, c, d;
ErrorCode rv;
rv = BigNum_Initialize(&a);
if(rv != ERROR_SUCCESS)
return(rv);
rv = BigNum_Initialize(&b);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&a); /* and what if THIS fails??? */
return(rv);
}
rv = BigNum_Initialize(&c);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}
rv = BigNum_Initialize(&d);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&c);
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}
/* do some math */
rv = BigNum_Set(&b, 3);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&d);
BigNum_Free(&c);
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}
...
/* free buffers */
rv = BigNum_Free(&d);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&c);
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}
rv = BigNum_Free(&c);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}
rv = BigNum_Free(&b);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&a);
return(rv);
}
rv = BigNum_Free(&a);
if(rv != ERROR_SUCCESS)
return(rv);
return(ERROR_SUCCESS);
}
---
But this is nasty, with all those duplicated "free" blocks. What can
be done to relieve this code duplication? It's ugly, it hurts my
freaking eyes and my nose is screaming for relief. And it hurts
maintainability to no end -- what if we decide to add more capability
to MyFunc() that requires additional bignums? Oy... We'd have to
update _all those blocks_.
I was thinking about using a "goto", but Gotos are Bad, aren't they? I
can't believe I may have to use a goto! What about Djikstra's famous
letter? Is it possible that perhaps a goto may be GOOD here? Because
with a goto this would all seem much simpler. If we violate Djikstra,
we get:
---
ErrorCode MyFunc()
{
BigNum a, b, c, d;
ErrorCode rv;
rv = BigNum_Initialize(&a); if(rv != ERROR_SUCCESS) goto
fail0;
rv = BigNum_Initialize(&b); if(rv != ERROR_SUCCESS) goto
fail1;
rv = BigNum_Initialize(&c); if(rv != ERROR_SUCCESS) goto
fail2;
rv = BigNum_Initialize(&d); if(rv != ERROR_SUCCESS) goto
fail3;
/* do some math */
rv = BigNum_Set(&b, 3); if(rv != ERROR_SUCCESS) goto fail4;
...
/* free buffers */
rv = BigNum_Free(&d); if(rv != ERROR_SUCCESS) goto fail3;
rv = BigNum_Free(&c); if(rv != ERROR_SUCCESS) goto fail2;
rv = BigNum_Free(&b); if(rv != ERROR_SUCCESS) goto fail1;
rv = BigNum_Free(&a); if(rv != ERROR_SUCCESS) goto fail0;
return(ERROR_SUCCESS);
fail4: BigNum_Free(&d);
fail3: BigNum_Free(&c);
fail2: BigNum_Free(&b);
fail1: BigNum_Free(&a);
fail0: return(rv);
}
I've got some stuff that looks like this:
---
ErrorCode MyFunc()
{
BigNum a, b, c, d;
ErrorCode rv;
rv = BigNum_Initialize(&a);
if(rv != ERROR_SUCCESS)
return(rv);
rv = BigNum_Initialize(&b);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&a); /* and what if THIS fails??? */
return(rv);
}
rv = BigNum_Initialize(&c);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}
rv = BigNum_Initialize(&d);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&c);
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}
/* do some math */
rv = BigNum_Set(&b, 3);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&d);
BigNum_Free(&c);
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}
...
/* free buffers */
rv = BigNum_Free(&d);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&c);
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}
rv = BigNum_Free(&c);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}
rv = BigNum_Free(&b);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&a);
return(rv);
}
rv = BigNum_Free(&a);
if(rv != ERROR_SUCCESS)
return(rv);
return(ERROR_SUCCESS);
}
---
But this is nasty, with all those duplicated "free" blocks. What can
be done to relieve this code duplication? It's ugly, it hurts my
freaking eyes and my nose is screaming for relief. And it hurts
maintainability to no end -- what if we decide to add more capability
to MyFunc() that requires additional bignums? Oy... We'd have to
update _all those blocks_.
I was thinking about using a "goto", but Gotos are Bad, aren't they? I
can't believe I may have to use a goto! What about Djikstra's famous
letter? Is it possible that perhaps a goto may be GOOD here? Because
with a goto this would all seem much simpler. If we violate Djikstra,
we get:
---
ErrorCode MyFunc()
{
BigNum a, b, c, d;
ErrorCode rv;
rv = BigNum_Initialize(&a); if(rv != ERROR_SUCCESS) goto
fail0;
rv = BigNum_Initialize(&b); if(rv != ERROR_SUCCESS) goto
fail1;
rv = BigNum_Initialize(&c); if(rv != ERROR_SUCCESS) goto
fail2;
rv = BigNum_Initialize(&d); if(rv != ERROR_SUCCESS) goto
fail3;
/* do some math */
rv = BigNum_Set(&b, 3); if(rv != ERROR_SUCCESS) goto fail4;
...
/* free buffers */
rv = BigNum_Free(&d); if(rv != ERROR_SUCCESS) goto fail3;
rv = BigNum_Free(&c); if(rv != ERROR_SUCCESS) goto fail2;
rv = BigNum_Free(&b); if(rv != ERROR_SUCCESS) goto fail1;
rv = BigNum_Free(&a); if(rv != ERROR_SUCCESS) goto fail0;
return(ERROR_SUCCESS);
fail4: BigNum_Free(&d);
fail3: BigNum_Free(&c);
fail2: BigNum_Free(&b);
fail1: BigNum_Free(&a);
fail0: return(rv);
}