473,756 Members | 1,969 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Cleanup patterns

MQ
Hi all

I am just wondering how most people implement cleanup in C functions.
In particular, if the function opens a number of resources, these need
to be released properly should an error occur at any point in the
function (as well as at the end if successful). C++ has exceptions,
the only way I can see to do this neatly in C is to use goto
statements. Is my method of implementing cleanup good, or are their
better ways. Here is an example, which uses the global errno to store
the error.

#define CLEANUP(err) ({errno = (err); goto cleanup})

int example_functio n()
{
SOMETYPE * a,b,c;
errno = 0;

if(!(a = malloc(sizeof(a ))))
CLEANUP(ENOMEM) ;

if(!(b = malloc(sizeof(b ))))
CLEANUP(ENOMEM) ;

if(!(c = malloc(sizeof(c ))))
CLEANUP(ENOMEM) ;

/* do something here */

cleanup:
if(a)
free(a);
if(b);
free(b);
if(c)
free(c);
if(errno)
return -1;
return 0;
}

Nov 29 '06 #1
69 3229

MQ wrote:
Hi all

I am just wondering how most people implement cleanup in C functions.
In particular, if the function opens a number of resources, these need
to be released properly should an error occur at any point in the
function (as well as at the end if successful). C++ has exceptions,
the only way I can see to do this neatly in C is to use goto
statements. Is my method of implementing cleanup good, or are their
better ways. Here is an example, which uses the global errno to store
the error.

#define CLEANUP(err) ({errno = (err); goto cleanup})
Don't use macros with jumps and what not.
int example_functio n()
{
SOMETYPE * a,b,c;
b and c are not pointers [or at least not at the same level as a]
errno = 0;

if(!(a = malloc(sizeof(a ))))
CLEANUP(ENOMEM) ;

if(!(b = malloc(sizeof(b ))))
CLEANUP(ENOMEM) ;

if(!(c = malloc(sizeof(c ))))
CLEANUP(ENOMEM) ;
I'd do simply

a = malloc(sizeof(* a));
if (a == NULL) { errno = outofmem; goto ERR_A; }
b = ...
if (b == NULL) { errno = outofmem; goto ERR_B; }
....

Then at the end have

errno = 0;

ERR_C:
free(b);
ERR_B:
free(a);
ERR_A:
return errno;
}

Makes the code easy to follow and doesn't involve nasty if's all over
the place (e.g. if you avoided goto all together..)

Tom

Nov 29 '06 #2
MQ wrote:
Hi all

I am just wondering how most people implement cleanup in C functions.
In particular, if the function opens a number of resources, these need
to be released properly should an error occur at any point in the
function (as well as at the end if successful). C++ has exceptions,
the only way I can see to do this neatly in C is to use goto
statements.
In C, it's typical to use nested if's, and/or carefully
initialized variables, and/or decomposition into multiple
functions, and/or goto.
Is my method of implementing cleanup good, or are their
better ways. Here is an example, which uses the global errno to store
the error.
Your method is Bad(tm). For starters, it won't compile.
That could be fixed by changing the macro definition, but then
you'd be invoking undefined behavior if either of the first two
malloc() calls failed. Also, Standard C doesn't define ENOMEM,
and `errno!=0' is not a valid test for failure.

All of these problems are easily fixed or worked around, but
consider: You've advanced CLEANUP as, essentially, a way to help
write better programs. Since it demonstrably has *not* helped
you to write a better program, perhaps it's time to question its
effectiveness, no?
#define CLEANUP(err) ({errno = (err); goto cleanup})

int example_functio n()
{
SOMETYPE * a,b,c;
errno = 0;

if(!(a = malloc(sizeof(a ))))
CLEANUP(ENOMEM) ;

if(!(b = malloc(sizeof(b ))))
CLEANUP(ENOMEM) ;

if(!(c = malloc(sizeof(c ))))
CLEANUP(ENOMEM) ;

/* do something here */

cleanup:
if(a)
free(a);
if(b);
free(b);
if(c)
free(c);
if(errno)
return -1;
return 0;
}
--
Eric Sosman
es*****@acm-dot-org.invalid

Nov 29 '06 #3
MQ

Eric Sosman wrote:
MQ wrote:
Hi all

I am just wondering how most people implement cleanup in C functions.
In particular, if the function opens a number of resources, these need
to be released properly should an error occur at any point in the
function (as well as at the end if successful). C++ has exceptions,
the only way I can see to do this neatly in C is to use goto
statements.

In C, it's typical to use nested if's, and/or carefully
initialized variables, and/or decomposition into multiple
functions, and/or goto.
Is my method of implementing cleanup good, or are their
better ways. Here is an example, which uses the global errno to store
the error.

Your method is Bad(tm). For starters, it won't compile.
That could be fixed by changing the macro definition, but then
you'd be invoking undefined behavior if either of the first two
malloc() calls failed. Also, Standard C doesn't define ENOMEM,
and `errno!=0' is not a valid test for failure.
Hi Eric

I did throw this together rather quickly and no doubt there will be a
number of errors, but after posting I fixed these problems and it does
compile fine. Ignoring this, I just want to know if the general
structure of the code is good practise. You should be able to
ascertain what I am trying to achieve...
MQ.

Nov 29 '06 #4
MQ wrote:
Eric Sosman wrote:
>>MQ wrote:

>>>Hi all

I am just wondering how most people implement cleanup in C functions.
In particular, if the function opens a number of resources, these need
to be released properly should an error occur at any point in the
function (as well as at the end if successful). C++ has exceptions,
the only way I can see to do this neatly in C is to use goto
statements .

In C, it's typical to use nested if's, and/or carefully
initialized variables, and/or decomposition into multiple
functions, and/or goto.

>>>Is my method of implementing cleanup good, or are their
better ways. Here is an example, which uses the global errno to store
the error.

Your method is Bad(tm). For starters, it won't compile.
That could be fixed by changing the macro definition, but then
you'd be invoking undefined behavior if either of the first two
malloc() calls failed. Also, Standard C doesn't define ENOMEM,
and `errno!=0' is not a valid test for failure.


Hi Eric

I did throw this together rather quickly and no doubt there will be a
number of errors, but after posting I fixed these problems and it does
compile fine. Ignoring this, I just want to know if the general
structure of the code is good practise. You should be able to
ascertain what I am trying to achieve...
It appears you are trying to achieve what I described as
typical: "nested if's, and/or carefully initialized variables,
and/or decomposition into multiple functions, and/or goto."
My original question remains: Given that the attempt led you
into four different errors (and perhaps more in the "fixed"
version we haven't seen yet), do you still think you're going
about things in the best way possible? Note that "it does
compile fine" and "it is correct" are not the same thing!

--
Eric Sosman
es*****@acm-dot-org.invalid

Nov 29 '06 #5
MQ wrote:
>
I am just wondering how most people implement cleanup in C
functions. In particular, if the function opens a number of
resources, these need to be released properly should an error
occur at any point in the function (as well as at the end if
successful). C++ has exceptions, the only way I can see to do
this neatly in C is to use goto statements. Is my method of
implementing cleanup good, or are their better ways. Here is an
example, which uses the global errno to store the error.

#define CLEANUP(err) ({errno = (err); goto cleanup})

int example_functio n()
{
SOMETYPE * a,b,c;
errno = 0;

if(!(a = malloc(sizeof(a ))))
CLEANUP(ENOMEM) ;

if(!(b = malloc(sizeof(b ))))
CLEANUP(ENOMEM) ;

if(!(c = malloc(sizeof(c ))))
CLEANUP(ENOMEM) ;

/* do something here */

cleanup:
if(a)
free(a);
if(b);
free(b);
if(c)
free(c);
if(errno)
return -1;
return 0;
}
I would implement that as:

int example(void)
{
SOMETYPE *a, *b, *c;

errno = 0;
a = b = c = NULL;
if (!(a = malloc(sizeof *a))) errno = ENOMEM;
else if (!(b = malloc(sizeof *b))) errno = ENOMEM;
else if (!(c = malloc(sizeof *c))) errno = ENOMEM
else {
/* dosomething here */
}
free(a); free(b); free(c);
return -(0 != errno);
}

Notice the absence of obfuscating macros. Also the routine no
longer frees undefined pointers or non-pointers. No goto needed,
although I do not hesitate to use them when appropriate. I would
normally choose different return values.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home .att.net>
Nov 29 '06 #6
MQ
It appears you are trying to achieve what I described as
typical: "nested if's, and/or carefully initialized variables,
and/or decomposition into multiple functions, and/or goto."
My original question remains: Given that the attempt led you
into four different errors (and perhaps more in the "fixed"
version we haven't seen yet), do you still think you're going
about things in the best way possible?
Umm, well, that was my question originally. I am looking for feedback.
And the question is more generic than the example above. I want to
know *generically* what are the best methods for implementing cleanup
in C functions. I can say for sure that *something* needs to be done,
as a function that holds potentially numerous resources cannot clean up
at the point of error, otherwise most of the code will be cleanup
stuff, and obscure the real task that the code is doing.

MQ.

Nov 29 '06 #7
MQ said:
Hi all

I am just wondering how most people implement cleanup in C functions.
I can't speak for most people, but I do it like this:

Attempt to acquire resource
If attempt succeeded
Use resource
Release resource
Else
Handle error
Endif

This code structure is recursively extensible, and functions are a fabulous
mechanism for keeping the indent level down.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 29 '06 #8
MQ wrote:
Hi all

I am just wondering how most people implement cleanup in C functions.
In particular, if the function opens a number of resources, these need
to be released properly should an error occur at any point in the
function (as well as at the end if successful). C++ has exceptions,
the only way I can see to do this neatly in C is to use goto
statements. Is my method of implementing cleanup good, or are their
better ways. Here is an example, which uses the global errno to store
the error.

#define CLEANUP(err) ({errno = (err); goto cleanup})

int example_functio n()
{
SOMETYPE * a,b,c;
errno = 0;

if(!(a = malloc(sizeof(a ))))
CLEANUP(ENOMEM) ;

if(!(b = malloc(sizeof(b ))))
CLEANUP(ENOMEM) ;

if(!(c = malloc(sizeof(c ))))
CLEANUP(ENOMEM) ;

/* do something here */

cleanup:
if(a)
free(a);
if(b);
free(b);
if(c)
free(c);
if(errno)
return -1;
return 0;
}
This one I'd write (fixing a couple of things along the way) as:

int exampleFunction ()
{
SomeType *a = malloc( sizeof (*a) );
SomeType *b = malloc( sizeof (*b) );
SomeType *c = malloc( sizeof (*c) );
int status = a && b && c ? 0 : -1;
if (status == 0)
{
/* do what must be done */
}
free( a ), free( b ), free( c );
return status;
}

I don't think your example is complex enough to demonstrate whatever
value your macro might have.

--
Chris "Magenta - the best colour of sound" Dollin
"No-one here is exactly what he appears." G'kar, /Babylon 5/

Nov 29 '06 #9
CBFalconer wrote:
MQ wrote:
>>I am just wondering how most people implement cleanup in C
functions. In particular, if the function opens a number of
resources, these need to be released properly should an error
occur at any point in the function (as well as at the end if
successful) . C++ has exceptions, the only way I can see to do
this neatly in C is to use goto statements. Is my method of
implementin g cleanup good, or are their better ways. Here is an
example, which uses the global errno to store the error.

#define CLEANUP(err) ({errno = (err); goto cleanup})

int example_functio n()
{
SOMETYPE * a,b,c;
errno = 0;

if(!(a = malloc(sizeof(a ))))
CLEANUP(ENOMEM) ;

if(!(b = malloc(sizeof(b ))))
CLEANUP(ENOMEM) ;

if(!(c = malloc(sizeof(c ))))
CLEANUP(ENOMEM) ;

/* do something here */

cleanup:
if(a)
free(a);
if(b);
free(b);
if(c)
free(c);
if(errno)
return -1;
return 0;
}


I would implement that as:

int example(void)
{
SOMETYPE *a, *b, *c;

errno = 0;
a = b = c = NULL;
if (!(a = malloc(sizeof *a))) errno = ENOMEM;
else if (!(b = malloc(sizeof *b))) errno = ENOMEM;
else if (!(c = malloc(sizeof *c))) errno = ENOMEM
Missing a semicolon here, right after the possibly
undefined identifier ENOMEM.
else {
/* dosomething here */
}
free(a); free(b); free(c);
return -(0 != errno);
Note that free() is permitted to set errno to a non-zero
value. So might /* dosomething here */ if it were not a
comment.

errno is not a good holder for program state, because
it's "transient: " most library functions can change it at
will, whether or not any error has occurred. Park a value
in errno, and it may be "gone in sixty seconds."

--
Eric Sosman
es*****@acm-dot-org.invalid
Nov 29 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
2565
by: Design Pattern Catalog | last post by:
Thank you for your interest in "Design Patterns: Elements of Reusable Object-Oriented Design", by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. This message answers several frequently asked questions. If you thought you were asking for the source code, you must have made a mistake. Please try again! The "pattern home page", with all this information and more, is at...
6
1470
by: use dmgass at hotmail dot com | last post by:
I'm writing a module and when it is imported by a script I want some code automatically executed when the importing script is finished executing. I'd like it to execute before interactive mode is entered when executing the importing script from the command line. I don't want to have to impose that the importing script must call a function at it's end. Any help is greatly appreciated!!
32
2208
by: fatted | last post by:
I've written a function (clean_string) to remove characters from a string, but it looks clunky to me, and I'm sure there's a more 'C' like way of doing it (still learning), comments and advice welcome... -- #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void)
1
2374
by: Jay | last post by:
The GOF text is widely considered the definitive book on the topic. Design Patterns: Elements of Reusable Object-Oriented Softare, Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides Note, all the examples are in C++ but you can get through them with a little work.
13
6560
by: John Salerno | last post by:
Here are a few I'm considering: Design Patterns Explained : A New Perspective on Object-Oriented Design (2nd Edition) (Software Patterns Series) by Alan Shalloway Design Patterns C# by Steven John Metsker Design Patterns by Erich Gamma Head First Design Patterns by Elisabeth Freeman
12
1912
by: Jeff | last post by:
I'm just getting up to speed on OOP patterns (e.g, MVC) and I'm wondering how closely they are followed out in the real world. Do those of you who use them try to follow them as closely as possible and deviate only as necessary? Or do you only generally follow them; mix-n-match as necessary? Just wondering what I should be looking to accomplish with OOP patterns in general. Thanks!
1
4583
by: Jason S | last post by:
I haven't used try/catch/finally very much in Javascript. My function (let's call it try_it()) needs to call a function that could throw an exception (let's call it dangerous()) with some setup() beforehand and cleanup() afterwards. What I want to make sure cleanup() is called whether or not dangerous throws an exception, and if it does throw an exception, rethrow the exception to whatever is calling try_it(). In C++ this is much easier...
7
3105
by: =?Utf-8?B?bWF2cmlja18xMDE=?= | last post by:
Hi, I would like to know more about design patterns and specifically using C#. Can any one recommend a good book? Thanks
4
2667
by: IanWright | last post by:
I've got a section of a program that I can't quite get to work. I'm fairly sure its something very simple/trivial but it looks correct to me, so if someone could help me fix the problem, and explain what it is that is wrong, that would be great... I've posted a sample of code, which is the bit of interest: class Solution { private: int *HeuristicTours; public: int* GetTours() {
0
10031
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
9838
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9708
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8709
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6534
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5140
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5302
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3354
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2665
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.