473,388 Members | 1,377 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,388 software developers and data experts.

clean exit - suggestions?

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)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_failed)
{
// blah blah
// free mem1, mem2, ...
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
Jul 22 '05 #1
15 2330
lallous wrote:

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)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_failed)
{
// blah blah
// free mem1, mem2, ...
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?


use a std::string instead of dynamically allocated character arrays.

#include <string>

void fnc()
{
std::string mem1;
std::string mem2;

mem1 = "Hallo";
mem2 = "World";

// look Ma! I don't have to do anything. mem1 and mem2
// will free the allocated memory all by themselfs
}

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #2
"Karl Heinz Buchegger" <kb******@gascad.at> wrote in message
news:3F***************@gascad.at...
lallous wrote:

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)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_failed)
{
// blah blah
// free mem1, mem2, ...
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?


use a std::string instead of dynamically allocated character arrays.

#include <string>

void fnc()
{
std::string mem1;
std::string mem2;

mem1 = "Hallo";
mem2 = "World";

// look Ma! I don't have to do anything. mem1 and mem2
// will free the allocated memory all by themselfs
}

--
Karl Heinz Buchegger
kb******@gascad.at


Hello,

Your solution is a hint...but I am using such buffers to do file i/o and
cannot really use std::string....

And sometimes I have code like:
fclose(fp1); fclose(fp2); free(mem1); myObj->DeInit(); blah blah...
So you see how the cleanup code is not always solved by using objects...so
my question was how to avoid repeating the cleanup code over and over in
case I want to return in the middle of the function.

--
Elias
Jul 22 '05 #3
"lallous" <la*****@lgwm.org> wrote in message
news:bt************@ID-161723.news.uni-berlin.de...
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)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_failed)
{
// blah blah
// free mem1, mem2, ...
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?


The problem with code you posted is code duplication (= maintenance
headache, which will no doubt lead to bugs later) and that it is not
exception safe.

If it is just freeing char* that is bothering you, why not use the
std::string class?

#include <string>
void fnc()
{
std::string mem1, mem2, mem3, mem4;

// lots of code...
// lots of code and condition checks
if (condition_failed)
{
// blah blah
// No need to explicitly free mem1, mem2, mem3, mem4!
return;
}

if (condition2_failed)
{
// blah blah
// No need to explicitly free mem1, mem2, mem3, mem4!
return;
}

// No need to explicitly free mem1, mem2, mem3, mem4!
}

The advantage of this is not only that all memory used by the string is
automatically released, no matter how the function exits (return or
exception), but also that string manipulation with the std::string is much
easier to code and understand. Similary the std::vector class is an
excellent replacement for dynamically created arrays; also with this class
there is no need to worry about explicit memory management.

For other tasks that need to be done when a functions exits, consider using
the RAII idiom
(http://c2.com/cgi/wiki?ResourceAcqui...nitialization). An example of
RAII is the std::auto_ptr class. The basic idea of the RAII idiom is to
create a local object which has a destructor that perfoms the operations
necessary when the function is exited (the destructor essentially replaces
the non-standard _finally clause). Since the destructor of local objects is
always called when the function exists, the destructor can perfom the
things you now do in the non-standard _finally() clause.

#include <iostream>
class AutoCleanup
{
public:
AutoCleanup();
~AutoCleanup()
{
std::cout << "AutoCleanup dtor" << std::endl
}
}

void fnc()
{
AutoCleanup tmp;
// lots of code and condition checks
if (condition_failed)
{
// The return statement causes
// AutoCleanup::~AutoCleanup to be called
return;
}

if (condition2_failed)
{
// The return statement causes
// AutoCleanup::~AutoCleanup to be called
return;
}

// When the function finishes
// AutoCleanup::~AutoCleanup will be called
}

Also when a exception is thrown the AutoCleanup::~AutoCleanup will be
called. The RAII idiom is a very handy technique which usefullness is not
restricted to releasing memory or other resources. For example for UI code
you could make a class the changes the mouse cursor to a hourglass on
construction and restores the previous mouse cursor on destruction:

class HourGlassCursor
{
public:
HourGlassCursor() : prev_(getCursor())
{
setCursor(crHourGlass);
}

~HourGlassCursor()
{
setCursor(prev_);
};

private:
Cursor prev_;
};

void calculate()
{
HourGlassCursor hgc;
// do some lengthy processing...
}

The cursor will always be restored, even if an exception is thrown.
--
Peter van Merkerk
peter.van.merkerk(at)dse.nl




Jul 22 '05 #4
lallous wrote:
Hello,

I have a function like:
...

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?


Putting your function into a class and writing an additional member function
cleanup() to close files and delete the buffers would help. Addionally you
could write a class (called eg. Buffer) to encapsule your char buffers and
use auto_ptr<Buffer> in your code then.

--
To get my real email adress, remove the two onkas
--
Dipl.-Inform. Hendrik Belitz
Central Institute of Electronics
Research Center Juelich
Jul 22 '05 #5
lallous wrote:
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)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_failed)
{
// blah blah
// free mem1, mem2, ...
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


Put the cleanup code in the destructor of an automatic variable. The
resource acquisition probably should be done in a member initialization
list, too. Google. for RAII.

#include <cstddef>

template< typename T >
struct Mem
{
Mem( size_t z ): p( new T [ z ] ) { }

~Mem( ) { /* "blah blah," as you say. */ delete [ ] p; }

T* p;
private:
Mem( Mem const& ) { /* Don't copy the Mem objects. */ }
};

void fnc( )
{
// lots of code...

Mem< char > mem1, mem2, mem3, mem4;

// lots of code and condition checks

if (condition_failed)
{
return;
}

if (condition2_failed)
{
return;
}

// here the end of routine
}

Jul 22 '05 #6
In article <bt************@ID-161723.news.uni-berlin.de>, lallous wrote:
"Karl Heinz Buchegger" <kb******@gascad.at> wrote in message
news:3F***************@gascad.at... Your solution is a hint...but I am using such buffers to do file i/o and
cannot really use std::string....

And sometimes I have code like:
fclose(fp1); fclose(fp2); free(mem1); myObj->DeInit(); blah blah...
So use your own buffer class that wraps a pointer to the dynamic string:

class buf {
char* mem;
public:
buf():mem(NULL) {}
buf (const char* x, int len) : mem (new char[len]) {
copy(x,x+len,mem);
}
void clear() { delete[] mem; mem = NULL; }

~buf() { delete [] mem; }
};
class Foo
{
FILE * fp1, *fp2;
auto_ptr<myObj> myObj;
Foo& operator=(const Foo&); // disable copy construct and assign
Foo(const Foo&);
public:
~Foo() {
fclose(fp1); fclose(fp2); buf.clear(); myObj->DeInit();
...
...
};

If you want your code to be exception safe, it would probably be a good idea
to wrap your file pointer in a class that handles closing the files too.
So you see how the cleanup code is not always solved by using objects...so


Yes it is. You just need the right object.

Cheers,
--
Donovan Rebbechi
http://pegasus.rutgers.edu/~elflord/
Jul 22 '05 #7
lallous wrote:


Hello,

Your solution is a hint...but I am using such buffers to do file i/o and
cannot really use std::string....

then use something else which has the same semantics (destroy dynamically
allocated memory when the object goes out of scope)

#include <vector>

void fnc()
{
std::vector<unsigned char> mem1;
std::vector<unsigned char> mem2;

mem1.resize( 200 ); // tell mem1 that I need 2 unsigned chars
mem2.resize( 500 ); // and mem2 will need 500 unsigned chars

mem1[20] = 5;
mem2[80] = 8;

// look Ma! I don't have to do anything. mem1 and mem2
// will free the allocated memory all by themselfs
}
And sometimes I have code like:
fclose(fp1); fclose(fp2); free(mem1); myObj->DeInit(); blah blah...
So you see how the cleanup code is not always solved by using objects...
It can *always* be solved by putting the thing you need to manage into
a class of its own. In fact that is the whole point of the RAII
idiom. The destructor gets called when the object goes out of scope
no matter how this is achieved. And the destructor is responsible for
deleting the dynamically managed resource (be it some memory, or a file
handle, or a modem or whatever).
so
my question was how to avoid repeating the cleanup code over and over in
case I want to return in the middle of the function.


Encapsulate the resource in a class and put the cleanup code into the destructor.
For some common types of resources this has already be done in your library,
eg std::string, std::vector, std::map, io streams, etc..

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #8
On Fri, 9 Jan 2004 14:27:29 +0200, "lallous" <la*****@lgwm.org> wrote:
Your solution is a hint...but I am using such buffers to do file i/o and
cannot really use std::string....

And sometimes I have code like:
fclose(fp1); fclose(fp2); free(mem1); myObj->DeInit(); blah blah...
shared_ptr<FILE> fp1(fopen("Filename", "r+"), fclose);

shared_ptr<MyObject> myObj(myObj, mem_fn(&MyObject::DeInit));
So you see how the cleanup code is not always solved by using objects...so
my question was how to avoid repeating the cleanup code over and over in
case I want to return in the middle of the function.


Use some kind of scope guard class. boost::shared_ptr is good for most
uses (particularly when combined with boost::bind and boost::mem_fn).
You might prefer an alternative such as:

http://www.cuj.com/documents/s=8000/...p1812alexandr/

Note that there should soon be std::shared_ptr, std::bind and
std::mem_fn - they are already in the draft standard library
extension.

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #9
On Fri, 09 Jan 2004 14:14:28 +0100 in comp.lang.c++, Hendrik Belitz
<ho**************@fz-juelich.de> was alleged to have written:
could write a class (called eg. Buffer) to encapsule your char buffers and
use auto_ptr<Buffer> in your code then.


std::auto_ptr<> cannot be used for this purpose because it uses "delete"
of the owned pointer, and not "delete[]"

Jul 22 '05 #10
"tom_usenet" <to********@hotmail.com> wrote in message
news:0s********************************@4ax.com...
On Fri, 9 Jan 2004 14:27:29 +0200, "lallous" <la*****@lgwm.org> wrote:
Your solution is a hint...but I am using such buffers to do file i/o and
cannot really use std::string....

And sometimes I have code like:
fclose(fp1); fclose(fp2); free(mem1); myObj->DeInit(); blah blah...


shared_ptr<FILE> fp1(fopen("Filename", "r+"), fclose);

shared_ptr<MyObject> myObj(myObj, mem_fn(&MyObject::DeInit));
So you see how the cleanup code is not always solved by using objects...somy question was how to avoid repeating the cleanup code over and over in
case I want to return in the middle of the function.


Use some kind of scope guard class. boost::shared_ptr is good for most
uses (particularly when combined with boost::bind and boost::mem_fn).
You might prefer an alternative such as:

http://www.cuj.com/documents/s=8000/...p1812alexandr/

Note that there should soon be std::shared_ptr, std::bind and
std::mem_fn - they are already in the draft standard library
extension.

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html


Thanks to all who shared their comments.

I liked most the vector<char> instead of allocating a char * w/ new char[].
Also liked the shared_ptr<FILE> ... .

I am still new to C++ and was expecting some solution that doesn't involve
objects as the STD library and other objects are loaded with lots of code
and checking which makes the code a bit slower.

Will ask this again in comp.lang.c to get yet more approaches.

--
Elias
Jul 22 '05 #11
On Mon, 12 Jan 2004 17:15:19 +0200, "lallous" <la*****@lgwm.org>
wrote:
Thanks to all who shared their comments.

I liked most the vector<char> instead of allocating a char * w/ new char[].
Also liked the shared_ptr<FILE> ... .

I am still new to C++ and was expecting some solution that doesn't involve
objects as the STD library and other objects are loaded with lots of code
and checking which makes the code a bit slower.


Code using standard libraries tends to be faster than code that
doesn't. Matching the optimization effort your library implementor has
gone to for the general case container can be hard even for a specific
case. In any case, the work is generally not worth it - improving
algorithms typically gives you more of a speed up.

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #12
lallous wrote:

I liked most the vector<char> instead of allocating a char * w/ new char[].
Also liked the shared_ptr<FILE> ... .

I am still new to C++ and was expecting some solution that doesn't involve
objects as the STD library
Then you are reinventing the wheel for no good reason.
and other objects are loaded with lots of code
and checking which makes the code a bit slower.
I bet that you will not be able to beat the performance of std::vector
(If used right) with homegrown code by more then 5%.

Will ask this again in comp.lang.c to get yet more approaches.

--
Elias

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #13
> 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)
// (etc.)


Assuming you don't like the suggestions offered so far (ie. create
a class where your cleanup code runs in the destructor), you
could do this:

void fnc() {
char *mem1 = 0, *mem2 = 0, *mem3 = 0, *mem4 = 0;
try {
// lots of code
if (condition1_failed) {
// condition1-specific cleanup code
}
}
delete mem1; delete mem2; delete mem3; delete mem4;
}

There is actually no need for __finally and __leave, you can
always structure your function so that "try" and "catch" are
sufficient.
Jul 22 '05 #14
"lallous" <la*****@lgwm.org> wrote in message news:<bt************@ID-161723.news.uni-berlin.de>...
[snip]
Any better way, other than goto or compiler specific solution?


Just in case nobody explicitly stated the rule to apply here.

Resource allocation should usually happen in a class.
Resource de-allocation should usually happen in the dtor of a class.

This applies not just to memory, but files, and anything else
that has to be allocated, gotten, initialized, etc. So when
you get into things like networking, for example, and you
have to open a connection, that should be done in a class and
given back in the dtor.

Then you create an instance of a class and have that object do
the allocation. When the object goes out of scope, the dealloc
hapens automatically. This will work properly wether it happens
because you returned normally form the function, or because you
trapped an error and aborted, or because some sub-component
threw an exception.

The advantages of this are many. For example, you can now start
working on making your code exception safe. You can have your
functions throw exceptions and catch them with some assurance
that you won't have resource leaks. And you won't have to struggle
to remember all the stuff you allocated, and in what order,
so you can deallocate it on error conditions.

This is why so many folks were suggesting you use the std string
objects. (Well, one reason.)
Socks
Jul 22 '05 #15

"lallous" <la*****@lgwm.org> wrote in message
news:bt************@ID-161723.news.uni-berlin.de...
"tom_usenet" <to********@hotmail.com> wrote in message
news:0s********************************@4ax.com...
On Fri, 9 Jan 2004 14:27:29 +0200, "lallous" <la*****@lgwm.org> wrote:
Your solution is a hint...but I am using such buffers to do file i/o andcannot really use std::string....

And sometimes I have code like:
fclose(fp1); fclose(fp2); free(mem1); myObj->DeInit(); blah blah...
shared_ptr<FILE> fp1(fopen("Filename", "r+"), fclose);

shared_ptr<MyObject> myObj(myObj, mem_fn(&MyObject::DeInit));
So you see how the cleanup code is not always solved by using objects...somy question was how to avoid repeating the cleanup code over and over incase I want to return in the middle of the function.


Use some kind of scope guard class. boost::shared_ptr is good for most
uses (particularly when combined with boost::bind and boost::mem_fn).
You might prefer an alternative such as:

http://www.cuj.com/documents/s=8000/...p1812alexandr/

Note that there should soon be std::shared_ptr, std::bind and
std::mem_fn - they are already in the draft standard library
extension.

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html


Thanks to all who shared their comments.

I liked most the vector<char> instead of allocating a char * w/ new

char[]. Also liked the shared_ptr<FILE> ... .

I am still new to C++ and was expecting some solution that doesn't involve
objects as the STD library and other objects are loaded with lots of code
and checking which makes the code a bit slower.
"lots of <source> code" != "lots of machine instructions" - atleast in C++ -
release/optimized builds with any good compiler will only generate the code
that's actually used.
Will ask this again in comp.lang.c to get yet more approaches.


Sounds like this was your predisposition anyway.

Jeff F
Jul 22 '05 #16

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

Similar topics

2
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...
10
by: lallous | last post by:
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...
7
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?...
0
by: Stefan Krah | last post by:
Hello, I'm trying to run a Python script as a Windows service with a defined shutdown. The script (enigma-client.py) handles the communications with the server in a distributed computing effort...
7
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....
2
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...
10
by: Simon | last post by:
As title. How to clean out VSWebCache? Any good way to do that? Thanks.
39
by: mathieu | last post by:
Hi there, I am trying to reuse a piece of code that was designed as an application. The code is covered with 'exit' calls. I would like to reuse it as a library. For that I renamed the 'main'...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
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,...
0
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...
0
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,...
0
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...

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.