473,803 Members | 3,422 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

clean exit - suggestion - C version

Hello,

This question was asked in comp.lang.c++ and the answers involved the use of
objects whose destructors are automatically called when getting out of
scope, however I was expecting suggestions that doesn't involve the use of
objects. So here is the question again.

I have a function like:

void fnc() {
char *mem1, *mem2, *mem3, *mem4;
FILE *fp1;
// lots of code...
// mem1, 2, 3, 4 got allocated
// lots of code and condition checks
if (condition_fail ed)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_fai led)
{
// blah blah
// free mem1, mem2, ...
fclose(fp1);
return;
}

// here the end of routine (clean exit code):
// free mem1, mem2, mem3, mem4
}

Usually, I would use compiler specific solution by putting most of the code
in __try() and the clean exit code in _finally() block then to reach the
clean exit code I would invoke __leave.

Or use lables and then goto clean_exit

Any better way, other than goto or compiler specific solution?

--
Elias
Nov 14 '05 #1
10 4125
"lallous" <la*****@lgwm.o rg> wrote in message
news:bt******** ****@ID-161723.news.uni-berlin.de...
Hello,
...
I have a function like:

void fnc() {
char *mem1, *mem2, *mem3, *mem4;
FILE *fp1;
// lots of code...
// mem1, 2, 3, 4 got allocated
// lots of code and condition checks
if (condition_fail ed)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_fai led)
{
// blah blah
// free mem1, mem2, ...
fclose(fp1);
return;
}

// here the end of routine (clean exit code):
// free mem1, mem2, mem3, mem4
}

Usually, I would use compiler specific solution by putting most of the code in __try() and the clean exit code in _finally() block then to reach the
clean exit code I would invoke __leave.

Or use lables and then goto clean_exit

Any better way, other than goto or compiler specific solution?


A never ending story... You will get that many replies as many posters there
are on Usenet ;-)

My prefered solution is:

void fnc (void)
{
char * const mem1 = something_that_ allocates_mem1( );
if (mem1)
{
char * const mem2 = something_that_ allocates_mem2( );
if (mem2)
{
/* ...etc. */
free(mem2);
}
free(mem1);
}
}

This has, IMO, two main advantages:
1. It's much clearer, variables are only declared where and when they are
actually used.
2. Memory is freed in the reverse order of allocation, which is usually
considered a good practice (though it should make no difference).

On the other hand, it may get a bit cumbersome if you have too many
variables to clear.

But as I said, it is all merely a matter of style. Use what you think is the
best (or your company coding guidelines dictate you).

Peter
Nov 14 '05 #2
Peter Pichler wrote:

"lallous" <la*****@lgwm.o rg> wrote in message
news:bt******** ****@ID-161723.news.uni-berlin.de...
...
I have a function like:

void fnc() {
char *mem1, *mem2, *mem3, *mem4;
FILE *fp1;
// lots of code...
// mem1, 2, 3, 4 got allocated
// lots of code and condition checks
if (condition_fail ed)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_fai led)
{
// blah blah
// free mem1, mem2, ...
fclose(fp1);
return;
}

// here the end of routine (clean exit code):
// free mem1, mem2, mem3, mem4
}
.... snip ...
A never ending story... You will get that many replies as many
posters there are on Usenet ;-)

My prefered solution is:

void fnc (void)
{
char * const mem1 = something_that_ allocates_mem1( );
if (mem1)
{
char * const mem2 = something_that_ allocates_mem2( );
if (mem2)
{
/* ...etc. */
free(mem2);
}
free(mem1);
}
}


and my version is:

void fnc(void)
{
char *cp1;
char *cp2;
char *cp3;
/* as needed */

if (!(cp1 = malloc(CP1SIZE) )) goto cp1fail;
else if (!(cp2 = malloc(CP2SIZE) )) goto cp2fail;
else if (!(cp3 = malloc(CP3SIZE) )) goto cp3fail;
else {
/* they all worked - use em */
}
cp3fail:
free(cp3);
cp2fail:
free(cp2);
cp1fail:
free(cp1);
}

which is easily extended/compressed to the things needed. For
cleanup with free we can rework this to eliminate the gotos and
simply use NULL initializations for the cpN, but the above
organization will work with more complex scenarios.

--
Chuck F (cb********@yah oo.com) (cb********@wor ldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home .att.net> USE worldnet address!
Nov 14 '05 #3
CBFalconer <cb********@yah oo.com> wrote in message news:<40******* ********@yahoo. com>...
Peter Pichler wrote:

"lallous" <la*****@lgwm.o rg> wrote in message
news:bt******** ****@ID-161723.news.uni-berlin.de...
...
I have a function like:

void fnc() {
char *mem1, *mem2, *mem3, *mem4;
FILE *fp1;
// lots of code...
// mem1, 2, 3, 4 got allocated
// lots of code and condition checks
if (condition_fail ed)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_fai led)
{
// blah blah
// free mem1, mem2, ...
fclose(fp1);
return;
}

// here the end of routine (clean exit code):
// free mem1, mem2, mem3, mem4
}

... snip ...

A never ending story... You will get that many replies as many
posters there are on Usenet ;-)

My prefered solution is:

void fnc (void)
{
char * const mem1 = something_that_ allocates_mem1( );
if (mem1)
{
char * const mem2 = something_that_ allocates_mem2( );
if (mem2)
{
/* ...etc. */
free(mem2);
}
free(mem1);
}
}


and my version is:

void fnc(void)
{
char *cp1;
char *cp2;
char *cp3;
/* as needed */

if (!(cp1 = malloc(CP1SIZE) )) goto cp1fail;
else if (!(cp2 = malloc(CP2SIZE) )) goto cp2fail;
else if (!(cp3 = malloc(CP3SIZE) )) goto cp3fail;
else {
/* they all worked - use em */
}
cp3fail:
free(cp3);
cp2fail:
free(cp2);
cp1fail:
free(cp1);
}

which is easily extended/compressed to the things needed. For
cleanup with free we can rework this to eliminate the gotos and
simply use NULL initializations for the cpN, but the above
organization will work with more complex scenarios.


My question was:
1)I have allocated lots of resources (memory, files, ...)
2)for some conditions other than allocation failures the code will
have to exit and clean up, but instead of cleaning up everytime and
repeating the clean up code, the clean up code must be written once
and called many times by some technique such as 'goto'

// here resources are allocated
// here some condition
if (failed)
{
// cleanup code
}
// some code
// some condition
if (failed2)
{
// same cleanup code as above.....
}
Nov 14 '05 #4
On Mon, 12 Jan 2004 22:00:37 -0800, lallous wrote:
Peter Pichler wrote:
> A never ending story... You will get that many replies as many
> posters there are on Usenet ;-)

:)
My question was:
1)I have allocated lots of resources (memory, files, ...)
2)for some conditions other than allocation failures the code will
have to exit and clean up, but instead of cleaning up everytime and
repeating the clean up code, the clean up code must be written once
and called many times by some technique such as 'goto'


Initialize all pointers to NULL.
Use true false value to indicate successful allocation of resources where
the handle itself (such as a file handle) can't be used to check if the
resource should be freed. If you detect an error use a goto.

This works for the simple cases, but I'd bet someone could come up with an
example where the method would fail.

int fn() {

char *mem1 = NULL;
char *mem2 = NULL;
char *mem3 = NULL;
char *mem4 = NULL;
FILE *fp1 = NULL;
int some_resource_f lag = 0;

int result;

/* allocate resources, goto cleanup on failure */

cleanup:
if (some_resource_ flag) free_some_resou rce();
if (fp1) fclose(fp1);
free(mem4);
free(mem3);
free(mem2);
free(mem1);

return result;

}
--
NPV

"the large print giveth, and the small print taketh away"
Tom Waits - Step right up

Nov 14 '05 #5
Nils Petter Vaskinn <no@spam.for.me .invalid> wrote in message news:<pa******* *************** ******@spam.for .me.invalid>...

I like all those solutions posted above, and have used them all
myself. What's not covered, however, is leaving the function the way
it is! :-D That's my current 'fave method'. Early programming exits
are supposedly a 'bad thing', but they occasionally have advantages
over the other methods when:

1. The cleanup code to be executed varies from exit to exit.
2. The remaining code is large, and doing it in one of the above
methods results in heavily indented code.

Using the other two methods, it's impossible to be consistent - it's
appropriate only occasionally. The 'early exit' method is useful more
frequently, but sometimes results in the redundant line or two.

In general, if early exits will give me what I want with no duplicate
code, or only one line, I'll use it. If the cleanup code is
significant, I use one of the methods outlined by the others. I prefer
the clean reading style you get with early exits, so I use it most
frequently. This is a change from my C coding style as a beginner.

//----------------------------------
// Here's an example of its use:
//----------------------------------
if (!A)
return; // error condition 1
if (!B)
return; // error condition 2
if (!C)
return; // error condition 3.

// If the code got here, it passed all the tests.
dofunction(D);
//----------------------------------
// Without it, the code would look like:
//----------------------------------
if (A)
if (B)
if (C)
dofunction(D);
else
return;
else
return;
else
return;

In this trivial example, the 'else returns' are optional and can be
left off... but if they're supposed to do cleanup, you can see where
this indentation could get quite large. Also, with this method, it's
easy to lose track of where you are in the 'if' hierarchy, and
inadvertantly execute some logic you weren't supposed to. I haven't
had that problem since switching to the 'early exit' style of
programming.
--Kamilche
Nov 14 '05 #6
On Tue, 13 Jan 2004 02:36:43 -0800, Kamilche wrote:
Nils Petter Vaskinn <no@spam.for.me .invalid> wrote in message
news:<pa******* *************** ******@spam.for .me.invalid>...

I like all those solutions posted above, and have used them all myself.
What's not covered, however, is leaving the function the way it is! :-D
That's my current 'fave method'. Early programming exits are supposedly
a 'bad thing', but they occasionally have advantages over the other
methods when:

1. The cleanup code to be executed varies from exit to exit. 2. The
remaining code is large, and doing it in one of the above methods
results in heavily indented code.
1. My suggestion to have a flag for each resource to indicate if it should
be freed or not will usually eliminate the need for different cleanups.
Since checking the flags takes care of the different cases

2. The goto method I described above shouldn't increase the indentation
level significantly unless you use a very bizarre style.

Using the other two methods, it's impossible to be consistent - it's
appropriate only occasionally. The 'early exit' method is useful more
frequently, but sometimes results in the redundant line or two.

In general, if early exits will give me what I want with no duplicate
code, or only one line, I'll use it. If the cleanup code is significant,
I use one of the methods outlined by the others. I prefer the clean
reading style you get with early exits, so I use it most frequently.
This is a change from my C coding style as a beginner.


[snip example]

Your early exit exaple doesn't really fit in this discussion since there
is no cleanup.

But "return;" and "return something;" can easily be replaced with

/* result = something if there is a return from the function */
goto cleanup;

If there was any cleanup to be done, so the body of the code would
essentially be the same as with early exit. But you avoid having the
cleanup code at every exit point.

What it all boils down to is trying to make the code easy to understand
and maintain. Your example is, so it's perfectly ok code (IMO) but I would
try to avoid early exit in some other cases (like in one single case
hidden deep within nested ifs and loops where a quick glance at the
function could lead one to believe it has only a single exit point.
--
NPV

"the large print giveth, and the small print taketh away"
Tom Waits - Step right up

Nov 14 '05 #7
lallous wrote:
CBFalconer <cb********@yah oo.com> wrote in message news:

.... snip ...

and my version is:

void fnc(void)
{
char *cp1;
char *cp2;
char *cp3;
/* as needed */

if (!(cp1 = malloc(CP1SIZE) )) goto cp1fail;
else if (!(cp2 = malloc(CP2SIZE) )) goto cp2fail;
else if (!(cp3 = malloc(CP3SIZE) )) goto cp3fail;
else {
/* they all worked - use em */
}
cp3fail:
free(cp3);
cp2fail:
free(cp2);
cp1fail:
free(cp1);
}

which is easily extended/compressed to the things needed. For
cleanup with free we can rework this to eliminate the gotos and
simply use NULL initializations for the cpN, but the above
organization will work with more complex scenarios.


My question was:
1)I have allocated lots of resources (memory, files, ...)
2)for some conditions other than allocation failures the code will
have to exit and clean up, but instead of cleaning up everytime and
repeating the clean up code, the clean up code must be written once
and called many times by some technique such as 'goto'


which is just what my pattern does. malloc/free are just one
examples of routines that setup and cleanup.

if (setupfails(par ams1)) goto clean1;
else if (setupfails(par ams2)) goto clean2;
else {
/* success */
}
clean2: cleanup(params1 );
clean1: cleanup(params2 );
--
Chuck F (cb********@yah oo.com) (cb********@wor ldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home .att.net> USE worldnet address!
Nov 14 '05 #8
> void fnc() {
char *mem1, *mem2, *mem3, *mem4;
FILE *fp1;
// lots of code...
// mem1, 2, 3, 4 got allocated
// lots of code and condition checks
if (condition_fail ed)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_fai led)
{
// blah blah
// free mem1, mem2, ...
fclose(fp1);
return;
}

// here the end of routine (clean exit code):
// free mem1, mem2, mem3, mem4
}


I have a method I use only when I feel it really clarifies the situation,
and I always comment it (with a few words) when I'm doing so. It assumes
that all pointers (or objects in your case) are set to such a state that
cleaning them when left untouched isn't a problem or that it is obvious when
they don't need to be cleaned.

char *mem1 = NULL, *mem2 = NULL, *mem3 = NULL;
/* or you could do this:
char *mem1, *mem2, *mem3;
mem1 = mem2 = mem3 = NULL;
*/

/* try-like exception construct */
do
{
mem1 = malloc(MEM1SIZE );
if ( !mem1 )
break;

/* do something here */

mem2 = malloc(MEM1SIZE );
if ( !mem2 )
break;

/* do something else here */

mem1 = malloc(MEM1SIZE );
if ( !mem3 )
break;

/* do even more here */
}
while ( 0 );

if ( mem1 ) free(mem1);
if ( mem2 ) free(mem2);
if ( mem3 ) free(mem3);

return;

The do { } while ( 0 ) will always be executed once. You could put a return
code in there if you want to as well.

I think it is a decent solutions, much like the goto solution, but the
reason I prefer this over the goto approach is because it is very obvious
what block of code is being "tried" and it bears a little more resemblance
to a real try/catch construct.

Hope this helps,

Martijn Haak
http://www.sereneconcepts.nl
Nov 14 '05 #9
Nils Petter Vaskinn <no@spam.for.me .invalid> wrote in message news:<pa******* *************** ******@spam.for .me.invalid>...
What it all boils down to is trying to make the code easy to understand
and maintain. Your example is, so it's perfectly ok code (IMO) but I would
try to avoid early exit in some other cases (like in one single case
hidden deep within nested ifs and loops where a quick glance at the
function could lead one to believe it has only a single exit point.


Yeah, consistency with the rest of the code is important! I use early
exits very frequently in a common set of modules, so when you're
reading it, exceptions are pulled out and 'legal code' is in a
straight line down the page. But if the code didn't use early exits so
heavily, I would hesitate to include it - it's best to follow the
convention of the existing codebase.

I read about a study they did on experienced programmers versus newbie
programmers. As long as the code did 'the expected thing' and followed
a convention of some sort, the experienced programmers were far more
productive. But if the code did it one way in this module, another way
in another module, and was relatively a mishmash, they were just as
unproductive as the newbie programmers.

Far from being the 'hobgoblin of little minds', consistency extends a
programmer's brainpower. Use it in the style most suited to YOUR
brain. :-)

--Kamilche
Nov 14 '05 #10

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

Similar topics

2
5104
by: Jason | last post by:
I have a number of arrays that are populated with database values. I need to determine which array has the highest ubound out of all the arrays. The array size will always change based on the database record. Therefore, I need to be able to throw the arrays into a function that will automatically determine the highest ubound array. I was wondering if anyone might have a clean function that can do this. I have created a function that...
15
2370
by: lallous | last post by:
Hello, I have a function like: void fnc() { char *mem1, *mem2, *mem3, *mem4; // lots of code... // mem1, 2, 3, 4 got allocated // lots of code and condition checks if (condition_failed)
0
1462
by: Steve Jorgensen | last post by:
Hi all, I had just participating in a small thread here about when to set recordset variables to Nothing when I ran into an interesting case in my own code that highlighted the need for a formal, centralized function to deal with this. The case that came up was that I have a class module that handles 2 recordsets that it must clean up at termination, but the termination should not assume that the recordsets have necessarily been...
7
2247
by: Felix Kater | last post by:
Hi, when I need to execute a general clean-up procedure (inside of a function) just before the function returns -- how do I do that when there are several returns spread over the whole function? My first approach: Use "while(1)" and "break", however this doesn't work if there is another loop inside (since I can't break two loops at the same time):
4
1807
by: Rick | last post by:
Hello, Below I create a static instance of an object, works well. public static BasicCounter GlobalCounter = new BasicCounter("GlobalCounter"); private void Page_Load(object sender, System.EventArgs e) { GlobalCounter.Increment();
2
1388
by: cj | last post by:
I want when someone clicks the X in the upper right corner of my program for it to run the sub I've put in for the exit item on the main menu (exitMenuItem_click)
232
13381
by: robert maas, see http://tinyurl.com/uh3t | last post by:
I'm working on examples of programming in several languages, all (except PHP) running under CGI so that I can show both the source files and the actually running of the examples online. The first set of examples, after decoding the HTML FORM contents, merely verifies the text within a field to make sure it is a valid representation of an integer, without any junk thrown in, i.e. it must satisfy the regular expression: ^ *?+ *$ If the...
7
3795
by: Ben | last post by:
Hi We are looking for a component that offers that offers the below for Tiff files: Image clean-up (deskew, despeckle) Printing capabilities from VB The ability to add text to image, e.g. time / date Nice to have:
2
4327
by: teddysnips | last post by:
This is sort of an addendum to my previous post entitled: "Restrict FE application to one user at a time". My preferred design is to have a table with a single row that contains the network name of the person currently connected to the database. The existence of the row will serve a) to allow the system to bump any other user who wishes to connect, and b) to inform such users of the name of the currently logged-on user. However, at...
0
9703
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9565
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10550
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
10295
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
10069
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
5501
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
5633
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3799
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2972
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.