By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,230 Members | 1,502 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,230 IT Pros & Developers. It's quick & easy.

The 'finally' debate

P: n/a

I was just reading through some old articles in the 'Why not develop new
language' thread and came across the finally debate.

Everytime I mention 'finally' to C++ programmers I get almost emotional
responses about why it is not needed in C++. I don't get that.

For example, consider the following code. Please note, I can only use
heap allocated objects in my current project (new/delete).

//
// Foo - Tries to foo. Can throw a FooException
//

void Foo()
{
try {
// Do your foo business that could throw a FooException
}

catch (...) {
// Cleanup your business
throw;
}

// Cleanup your business
}

Now, with finally I could do this:

void Foo()
{
try {
// Do your foo business that could throw a FooException
}

finally {
// Cleanup your business
}
}

Which I find *much* cleaner than the other example as there is no
need to do the cleanup twice.

Anyway, the debate is useless because we don't have finally. So my question
really is, how do people refactor the above to something nicer?

S.
Jul 22 '05 #1
Share this Question
Share on Google+
54 Replies


P: n/a

"Stefan Arentz" <st***********@gmail.com> wrote in message
news:87************@keizer.soze.com...

I was just reading through some old articles in the 'Why not develop new
language' thread and came across the finally debate.

Everytime I mention 'finally' to C++ programmers I get almost emotional
responses about why it is not needed in C++. I don't get that.

For example, consider the following code. Please note, I can only use
heap allocated objects in my current project (new/delete).

//
// Foo - Tries to foo. Can throw a FooException
//

void Foo()
{
try {
// Do your foo business that could throw a FooException
}

catch (...) {
// Cleanup your business
throw;
}

// Cleanup your business
}

Now, with finally I could do this:

void Foo()
{
try {
// Do your foo business that could throw a FooException
}

finally {
// Cleanup your business
}
}

Which I find *much* cleaner than the other example as there is no
need to do the cleanup twice.

Anyway, the debate is useless because we don't have finally. So my question really is, how do people refactor the above to something nicer?


Simple use a class with a destructor (it's because Java doesn't have
destructors that it needs finally)

void Foo()
{
FooBusiness biz;
// Do your foo business that could throw a FooException
}

The FooBusiness destructor does the cleanup. This way you do not even need a
try/catch

john
Jul 22 '05 #2

P: n/a

"Stefan Arentz" <st***********@gmail.com> skrev i en meddelelse
news:87************@keizer.soze.com...
[snip] Which I find *much* cleaner than the other example as there is no
need to do the cleanup twice.

Anyway, the debate is useless because we don't have finally. So my question really is, how do people refactor the above to something nicer?

S.


Hi Stefan

John Harrison has already answered your question. I just want to add that
you could check out boost for some of the smart pointers there. There is
also "scopeguard" for more special stuff.

/Peter
Jul 22 '05 #3

P: n/a
"John Harrison" <jo*************@hotmail.com> writes:
Simple use a class with a destructor (it's because Java doesn't have
destructors that it needs finally)

void Foo()
{
FooBusiness biz;
// Do your foo business that could throw a FooException
}

The FooBusiness destructor does the cleanup. This way you do not even need a
try/catch


but what's about this:

void bar()
{
char * my_ptr;
try
{
SomeObject instace;
my_ptr = new char[987];
// do something
instace.doSomehting() // throws an exception let's say MyExec
// work with pointer
delete my_ptr
}
catch(MyExec &exc)
{
delete my_ptr;
// error handling
}
}

Here it's necessary to duplicate code, another example would be file
handling.
Sometimes a finally - block can help.

Mayby someone cann tell me why this was not taken into C++

Kind regards,
Nicolas

--
| Nicolas Pavlidis | Elvis Presly: |\ |__ |
| Student of SE & KM | "Into the goto" | \|__| |
| pa****@sbox.tugraz.at | ICQ #320057056 | |
|-------------------University of Technology, Graz----------------|
Jul 22 '05 #4

P: n/a
"Peter Koch Larsen" <pk*****@mailme.dk> writes:
"Stefan Arentz" <st***********@gmail.com> skrev i en meddelelse
news:87************@keizer.soze.com...

[snip]
Which I find *much* cleaner than the other example as there is no
need to do the cleanup twice.

Anyway, the debate is useless because we don't have finally. So my

question
really is, how do people refactor the above to something nicer?

S.


Hi Stefan

John Harrison has already answered your question. I just want to add that
you could check out boost for some of the smart pointers there. There is
also "scopeguard" for more special stuff.


I'm on a device that is too small to even include STL :)

S.
Jul 22 '05 #5

P: n/a
"John Harrison" <jo*************@hotmail.com> writes:

....
Simple use a class with a destructor (it's because Java doesn't have
destructors that it needs finally)

void Foo()
{
FooBusiness biz;
// Do your foo business that could throw a FooException
}

The FooBusiness destructor does the cleanup. This way you do not even need a
try/catch


I don't buy this for two reasons.

Wrapper classes introduce more code. I would like to use less code. I also
think it is a workaround and not a structural solution.

The above would simply move the exception handling and my finally problem
to a different place but it would still be present. I like it that you as
a user of the class don't have to deal with it anymore, but that is more
visual/convenience.

S.
Jul 22 '05 #6

P: n/a
* Nicolas Pavlidis:

but what's about this:

void bar()
{
char * my_ptr;
try
{
SomeObject instace;
my_ptr = new char[987];
// do something
instace.doSomehting() // throws an exception let's say MyExec
// work with pointer
delete my_ptr
}
catch(MyExec &exc)
{
delete my_ptr;
// error handling
}
}

void bar()
{
std::vector<char> my_ptr( 987 );
// do something
instace.doSomehting(); // semicolon here
}
Here it's necessary to duplicate code
Nope.

another example would be file handling.
Nope.

Sometimes a finally - block can help.
Yes.

Mayby someone cann tell me why this was not taken into C++


Because 'finally' is rarely needed in C++, and where it is needed it
indicates a redesign/refactoring is called for, and in the extremely
rare cases where that isn't an option, you can easily emulate it.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #7

P: n/a
al***@start.no (Alf P. Steinbach) writes:

....
Mayby someone cann tell me why this was not taken into C++


Because 'finally' is rarely needed in C++, and where it is needed it
indicates a redesign/refactoring is called for, and in the extremely
rare cases where that isn't an option, you can easily emulate it.


So how do you emulate it.

In my situation: no templates, no STL, no external libraries. Just bare
C++. GCC extensions are acceptable (3.3).

I've used inner functions (GCC extension) at one point.

void Foo()
{
vars;

void cleanup() {
cleanup vars;
}

try {
}

catch (...) {
cleanup();
throw;
}

cleanup();
}

But still, very yuckie :)

S.
Jul 22 '05 #8

P: n/a
On 21 Sep 2004 14:32:39 +0200, Stefan Arentz <st***********@gmail.com>
wrote:

I was just reading through some old articles in the 'Why not develop new
language' thread and came across the finally debate.

Everytime I mention 'finally' to C++ programmers I get almost emotional
responses about why it is not needed in C++. I don't get that.

For example, consider the following code. Please note, I can only use
heap allocated objects in my current project (new/delete).
So your current project isn't in standard C++, but rather a
company/personal dialect? I'm not sure we can help much with that...
//
// Foo - Tries to foo. Can throw a FooException
//

void Foo()
{
try {
// Do your foo business that could throw a FooException
}

catch (...) {
// Cleanup your business
throw;
}

// Cleanup your business
}

Now, with finally I could do this:

void Foo()
{
try {
// Do your foo business that could throw a FooException
}

finally {
// Cleanup your business
}
}

Which I find *much* cleaner than the other example as there is no
need to do the cleanup twice.

Anyway, the debate is useless because we don't have finally. So my question
really is, how do people refactor the above to something nicer?


void Foo()
{
//Do your foo business that could throw a FooException
}

where the foo business uses stack based objects whose destructors do
the cleanup. If your company doesn't allow that, then your company is
using mackled C++, and might be better off with C# or Java. At the
very least you can use std::auto_ptr.

Tom
Jul 22 '05 #9

P: n/a
>
I'm on a device that is too small to even include STL :)


If you design your classes with nice d'tors and only use classes
instead of new/malloc allocations, the problem is void. If you seem to
have a small device (WTF is this - a fridge?), then write optimized
code. The 'final' keyword would not do anything else than wrap your
code in a gargabe collector, which _is_ available as template classes
for those who cannot remember what they allocate. ;)
A good compiler will produce smal code from a template library, though
the source code might be big. And don't tell me you're compiling the
program _on_ the fride.
-Gernot


Jul 22 '05 #10

P: n/a
> In my situation: no templates, no STL, no external libraries. Just
bare
C++. GCC extensions are acceptable (3.3).


Beeeeeep!
No templates but bare C++? That's like "a tree, but without a trunk,
twigs and leaves". Only the bugs remain...
Jul 22 '05 #11

P: n/a
* Stefan Arentz:
al***@start.no (Alf P. Steinbach) writes:

...
Mayby someone cann tell me why this was not taken into C++


Because 'finally' is rarely needed in C++, and where it is needed it
indicates a redesign/refactoring is called for, and in the extremely
rare cases where that isn't an option, you can easily emulate it.


So how do you emulate it.


One way: you exit the inner block by throwing an exception so that all exits
are via exceptions. In the common catch handler you clean up (this is the
'finally' part) and then check whether the exception corresponds to a normal
return. If so, you do a normal return, otherwise you rethrow. I think this
should perhaps be tought in programming classes because it makes the cost of
'finally', what goes on behind the scenes, very explicit. On the other hand
there is the risk that what students know about they will use...

Another way: you pass references to things to be cleaned up to an object of a
locally declared class where the destructor implements the 'finally'.

But generally, use smart-pointers, RAII and exception-transparent code to
avoid the need for 'finally' handling: whenever you find yourself thinking
that 'finally' would be nice here, think about how much nicer if 'finally'
weren't needed here at all, i.e. if the code was refactored/redesigned! :o)

PS: No need to use gcc extension to define an inner function; where you
need it you can use a local class.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #12

P: n/a
Nicolas Pavlidis wrote:
"John Harrison" <jo*************@hotmail.com> writes:
Simple use a class with a destructor (it's because Java doesn't have
destructors that it needs finally)

void Foo()
{
FooBusiness biz;
// Do your foo business that could throw a FooException
}

The FooBusiness destructor does the cleanup. This way you do not even
need a try/catch
but what's about this:

void bar()
{
char * my_ptr;
try
{
SomeObject instace;
my_ptr = new char[987];
// do something
instace.doSomehting() // throws an exception let's say MyExec
// work with pointer
delete my_ptr
}
catch(MyExec &exc)
{
delete my_ptr;
// error handling
}
}

Here it's necessary to duplicate code, another example would be file
handling.


That's what std::auto_ptr is for:

void bar()
{
try
{
SomeObject instace;
std::auto_ptr<char> my_ptr(new char[987]);
// do something
instace.doSomehting() // throws an exception let's say MyExec
}
catch(MyExec &exc)
{
// error handling
}
}

See? You don't need to cleanup twice. You actually don't need to cleanup at
all. The destructor does the work for you, and that's how it's supposed to
be in C++.
Sometimes a finally - block can help.
It rather looks to me like a workaround for a design problem. In most cases,
you shouldn't need to deal with raw memory (and for those, you have
auto_ptr). In any other cases, the objects should do the cleanup themselves
on destruction. This is btw. a big advantage over GC languages that lack a
destructor (or at least lack one which is called at points that are exactly
defined)
Mayby someone cann tell me why this was not taken into C++


Probably nobody saw a need for it.

Jul 22 '05 #13

P: n/a
> > The FooBusiness destructor does the cleanup. This way you do not even
need a
try/catch


I don't buy this for two reasons.

Wrapper classes introduce more code. I would like to use less code. I also
think it is a workaround and not a structural solution.


Cleanup code are not part of the program logic, so it is very nice to avoid
it in the middle of the main code by putting it away in a destructor.
In addition the destructor approach prevents programmers from forgetting
cleanup code which leads to more stable applications.
So it is not a workaround but a significant improvement.

Niels Dybdahl
Jul 22 '05 #14

P: n/a
Tom Widmer <to********@hotmail.com> writes:
On 21 Sep 2004 14:32:39 +0200, Stefan Arentz <st***********@gmail.com>
wrote:

I was just reading through some old articles in the 'Why not develop new
language' thread and came across the finally debate.

Everytime I mention 'finally' to C++ programmers I get almost emotional
responses about why it is not needed in C++. I don't get that.

For example, consider the following code. Please note, I can only use
heap allocated objects in my current project (new/delete).


So your current project isn't in standard C++, but rather a
company/personal dialect? I'm not sure we can help much with that...


Well, it is code for firmware of a small device. Not very small, but small
enough that something like STL or Boost is not an option. Templates probably
are, but I've had no reason to use them yet and I would have to look into
object code size first.

Btw, I am very happy with the choise of C++ for this project. It has made
the code more robust and organized.

....
Anyway, the debate is useless because we don't have finally. So my question
really is, how do people refactor the above to something nicer?


void Foo()
{
//Do your foo business that could throw a FooException
}

where the foo business uses stack based objects whose destructors do
the cleanup. If your company doesn't allow that, then your company is
using mackled C++, and might be better off with C# or Java. At the
very least you can use std::auto_ptr.


So that would mean stack based objects and references? Get rid of all
pointers? It would probably mean a complete redesign of some things,
but I am willing to look into it. Is this the RAII stuff other people
were talking about?

S.
Jul 22 '05 #15

P: n/a
Stefan Arentz wrote:
al***@start.no (Alf P. Steinbach) writes:

...
> Mayby someone cann tell me why this was not taken into C++


Because 'finally' is rarely needed in C++, and where it is needed it
indicates a redesign/refactoring is called for, and in the extremely
rare cases where that isn't an option, you can easily emulate it.


So how do you emulate it.

In my situation: no templates, no STL, no external libraries. Just bare
C++. GCC extensions are acceptable (3.3).

I've used inner functions (GCC extension) at one point.

void Foo()
{
vars;

void cleanup() {
cleanup vars;
}

try {
}

catch (...) {
cleanup();
throw;
}

cleanup();
}

But still, very yuckie :)


Why don't the destructors of your "vars" do the cleanup? Anyway, you can
still use RAII:

void Foo()
{
struct whatever
{
// your variables

~whatever()
{
// cleanup
}
} vars;

// something that throws - or not.
}

No try, no catch, no finally needed. I admit that finally would be slightly
more convenient, but in my experience the cases where something like that
is needed are rare.

Jul 22 '05 #16

P: n/a
"Gernot Frisch" <Me@Privacy.net> writes:

I'm on a device that is too small to even include STL :)


If you design your classes with nice d'tors and only use classes
instead of new/malloc allocations, the problem is void. If you seem to
have a small device (WTF is this - a fridge?), then write optimized
code. The 'final' keyword would not do anything else than wrap your
code in a gargabe collector, which _is_ available as template classes
for those who cannot remember what they allocate. ;)
A good compiler will produce smal code from a template library, though
the source code might be big. And don't tell me you're compiling the
program _on_ the fride.


Neh, we keep the beer in the fridge. The device is a MIPS based device
with not too much RAM/Flash. Think <= 8MB. which needs to be shared
with a kernel, libraries some tools.

It is not very special, you just can't use all nice tricks that are
obvious on a normal 1GB workstation with a standard 80GB drive :)

S.
Jul 22 '05 #17

P: n/a

"Stefan Arentz" <st***********@gmail.com> wrote in message
news:87************@keizer.soze.com...
Tom Widmer <to********@hotmail.com> writes:
On 21 Sep 2004 14:32:39 +0200, Stefan Arentz <st***********@gmail.com>
wrote:

I was just reading through some old articles in the 'Why not develop newlanguage' thread and came across the finally debate.

Everytime I mention 'finally' to C++ programmers I get almost emotional
responses about why it is not needed in C++. I don't get that.

For example, consider the following code. Please note, I can only use
heap allocated objects in my current project (new/delete).


So your current project isn't in standard C++, but rather a
company/personal dialect? I'm not sure we can help much with that...


Well, it is code for firmware of a small device. Not very small, but small
enough that something like STL or Boost is not an option. Templates

probably

Is this because your compiler doesn't support STL/Boost? Or that you "think"
STL\Boost will require more memory?

Jeff F
Jul 22 '05 #18

P: n/a

"Stefan Arentz" <st***********@gmail.com> skrev i en meddelelse
news:87************@keizer.soze.com...
"Peter Koch Larsen" <pk*****@mailme.dk> writes:
"Stefan Arentz" <st***********@gmail.com> skrev i en meddelelse
news:87************@keizer.soze.com...

[snip]
Which I find *much* cleaner than the other example as there is no
need to do the cleanup twice.

Anyway, the debate is useless because we don't have finally. So my

question
really is, how do people refactor the above to something nicer?

S.


Hi Stefan

John Harrison has already answered your question. I just want to add that you could check out boost for some of the smart pointers there. There is
also "scopeguard" for more special stuff.


I'm on a device that is too small to even include STL :)

S.


I do not understand what you're saying. STL - or templates - does not
necessarily use more ressources than handwritten code. In your case it
should be safe.

/Peter
Jul 22 '05 #19

P: n/a

"Stefan Arentz" <st***********@gmail.com> skrev i en meddelelse
news:87************@keizer.soze.com...
"Gernot Frisch" <Me@Privacy.net> writes:

I'm on a device that is too small to even include STL :)


If you design your classes with nice d'tors and only use classes
instead of new/malloc allocations, the problem is void. If you seem to
have a small device (WTF is this - a fridge?), then write optimized
code. The 'final' keyword would not do anything else than wrap your
code in a gargabe collector, which _is_ available as template classes
for those who cannot remember what they allocate. ;)
A good compiler will produce smal code from a template library, though
the source code might be big. And don't tell me you're compiling the
program _on_ the fride.


Neh, we keep the beer in the fridge. The device is a MIPS based device
with not too much RAM/Flash. Think <= 8MB. which needs to be shared
with a kernel, libraries some tools.

It is not very special, you just can't use all nice tricks that are
obvious on a normal 1GB workstation with a standard 80GB drive :)

S.


Ahhh... that is lots and lots of space for C++.

/Peter
Jul 22 '05 #20

P: n/a
Stefan Arentz wrote:
Wrapper classes introduce more code.
I'd rate this as FUD. I just tested the following two translation units
with gcc on a StrongARM (I currently don't have access to gcc on an
Intel machine):

| // file tst1.cpp
| extern void f(int* i);
| void g() {
| int* i = new int(10);
| try { f(i); }
| catch ( ... ) {}
| delete i;
| }

This is as close at "finally" as possible: the try/catch is necessary
or some equivalent is necessary for the finally-clause, too. However,
deleting and rethrowing in the catch-clause would increase the code
even more (see tst3.cpp below).

| // file tst2.cpp
| extern void f(int* i);
| struct ptr {
| ptr(int* p): mp(p) {}
| ~ptr() { delete mp; }
| int* mp;
| };
| void g() {
| ptr p(new int(10));
| f(p.mp);
| }

It is admittedly more code but it can be placed into a header and
reused
in multiple places.

| // file tst3.cpp
| extern void f(int* i);
| void g() {
| int* i = new int(10);
| try { f(i); delete i; }
| catch ( ... ) { delete i; throw;}
| }

This is the manual approach without finally.

| // file tst4.cpp
| extern void f(int* i);
| template <typename T>
| struct ptr {
| ptr(T* p): mp(p) {}
| ~ptr() { delete mp; }
| T* get() { return mp; }
| private:
| ptr(ptr const&);
| void operator= (T const&);
| T* mp;
| };
| void g() {
| ptr p(new int(10));
| f(p.get());
| }

.... and I thought it is instructive to put this follow-blown version
using templates into it, too.

Compiled with "g++ -O4 -c tst*.cpp" I get the following:

| size *.o
| text data bss dec hex filename
| 172 16 0 188 bc tst1.o
| 180 6 0 186 ba tst2.o
| 228 16 0 244 f4 tst3.o
| 180 6 0 186 ba tst4.o

(I couldn't paste the results as they are on my PDA which is not
connected
to the machine I'm typing at).

Although the memory wasted by the non-automatic version is not too bad,
the automatic release is shorter, at minimum two bytes - not much but
you complained about use less code. Of course, if you want the correct
semantics, i.e. the exception shall not be swallowed, you have no
choice but go with automatic resource release if you don't want to
waste memory...
I would like to use less code. I also
think it is a workaround and not a structural solution.
I disagree: the idiom of handling resources is essential to effective
C++ programming.
The above would simply move the exception handling and my finally problem to a different place but it would still be present.
Where does the resource management class need a "finally"? All
exception
handling code is entirely generated by the compiler which will probably
generate something akin to finally but there is no need to care at all.
Also, resource management is centralized in one place. There is no
chance
of forgetting to clean up allocated resource (well, you can have a
plain
new but you shouldn't) because the finally clause is omitted. The code
is
not littered with clean-up code which is irrelevant to the actual
business
logic.
I like it that you as
a user of the class don't have to deal with it anymore, but that is more visual/convenience.


I disagree. Actually, if you are ever doing template programming you
will
appreciate that you don't have to know how to clean-up the objects you
are handling. You don't even need to care whether they need clean-up:
it
is the object's business, not yours. It is a logical step toward
encapsulation.
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.contendix.com> - Software Development & Consulting

Jul 22 '05 #21

P: n/a
Nicolas Pavlidis wrote:
void bar()
{
char * my_ptr;
Object should always be initialized, i.e. the above line shall be
replaced
by something like this if used at all:

| char * my_ptr = 0;
try
{
my_ptr = new char[987];
// do something
delete my_ptr
You allocated an array object you shall release an array object or
suffer
the effects of undefined behavior. The only correct way to delete an
array
object is using array delete:

| delete[] my_ptr;

This is explicit in 5.3.5 (expr.delete) paragraphs 2 and 3 of the
standard.
If you disagree with my statement, please provide a quote from the
standard
supporting your view.
Here it's necessary to duplicate code, another example would be file
handling.
Sometimes a finally - block can help.


Resource handling classes foster encapsulation and provide a better
approach
than a finally block could do. This was considered sufficient reason
for not
having finally blocks.
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.contendix.com> - Software Development & Consulting

Jul 22 '05 #22

P: n/a
Dietmar Kuehl wrote:
I just tested the following two translation units...

| ^^^

As it turns out, there are three kinds of persons: those who can count
and those who can't... I wrote this sentence when I wanted to post
just two translation units but it turned out to be reasonable to have
a total of four.
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.contendix.com> - Software Development & Consulting

Jul 22 '05 #23

P: n/a
Rolf Magnus wrote:

That's what std::auto_ptr is for:

void bar()
{
try
{
SomeObject instace;
std::auto_ptr<char> my_ptr(new char[987]);
// do something
instace.doSomehting() // throws an exception let's say MyExec
}
catch(MyExec &exc)
{
// error handling
}
}


That's double-plus-ungood Rolf. As I understand it, std::auto_ptr<>'s
destructor calls delete, not delete[]. So you invoked UB.

I suspect that with an array of char, it's probably OK (but not
necessarily), but suppose you did that with some class that had a
nontrivial destructor?
Jul 22 '05 #24

P: n/a
"Jeff Flinn" <NO****@nowhere.com> writes:
"Stefan Arentz" <st***********@gmail.com> wrote in message
news:87************@keizer.soze.com...
Tom Widmer <to********@hotmail.com> writes:
On 21 Sep 2004 14:32:39 +0200, Stefan Arentz <st***********@gmail.com>
wrote:

>
>I was just reading through some old articles in the 'Why not develop new >language' thread and came across the finally debate.
>
>Everytime I mention 'finally' to C++ programmers I get almost emotional
>responses about why it is not needed in C++. I don't get that.
>
>For example, consider the following code. Please note, I can only use
>heap allocated objects in my current project (new/delete).

So your current project isn't in standard C++, but rather a
company/personal dialect? I'm not sure we can help much with that...


Well, it is code for firmware of a small device. Not very small, but small
enough that something like STL or Boost is not an option. Templates

probably

Is this because your compiler doesn't support STL/Boost? Or that you "think"
STL\Boost will require more memory?


It is because both memory and flash is sparse. And I know for a fact that it
does not fit.

S.
Jul 22 '05 #25

P: n/a
"Peter Koch Larsen" <pk*****@mailme.dk> writes:

....
I'm on a device that is too small to even include STL :)

S.


I do not understand what you're saying. STL - or templates - does not
necessarily use more ressources than handwritten code. In your case it
should be safe.


Templates, yes probably. But including a 700K library in the firmware is
simply not an option.

S.
Jul 22 '05 #26

P: n/a
In message <87************@keizer.soze.com>, Stefan Arentz
<st***********@gmail.com> writes
Tom Widmer <to********@hotmail.com> writes:
On 21 Sep 2004 14:32:39 +0200, Stefan Arentz <st***********@gmail.com>
wrote:
>
>I was just reading through some old articles in the 'Why not develop new
>language' thread and came across the finally debate.
>
>Everytime I mention 'finally' to C++ programmers I get almost emotional
>responses about why it is not needed in C++. I don't get that.
>
>For example, consider the following code. Please note, I can only use
>heap allocated objects in my current project (new/delete).
So your current project isn't in standard C++, but rather a
company/personal dialect? I'm not sure we can help much with that...


Well, it is code for firmware of a small device. Not very small, but small
enough that something like STL or Boost is not an option. Templates probably
are,


??? Both STL and Boost _are_ mostly templates.
but I've had no reason to use them yet and I would have to look into
object code size first.
Unlikely to be significantly more than whatever you code manually.
Btw, I am very happy with the choise of C++ for this project. It has made
the code more robust and organized.
>Anyway, the debate is useless because we don't have finally. So my question
>really is, how do people refactor the above to something nicer?
void Foo()
{
//Do your foo business that could throw a FooException
}

where the foo business uses stack based objects whose destructors do
the cleanup. If your company doesn't allow that, then your company is
using mackled C++, and might be better off with C# or Java. At the
very least you can use std::auto_ptr.


So that would mean stack based objects and references? Get rid of all
pointers?


Not necessarily. Your stack based objects can still contain pointers,
but they take care of all the pointer management for you.
It would probably mean a complete redesign of some things,
but I am willing to look into it. Is this the RAII stuff other people
were talking about?

Just so.

--
Richard Herring
Jul 22 '05 #27

P: n/a
Dietmar Kuehl wrote:
Object should always be initialized, i.e. the above line shall be
replaced
by something like this if used at all:

| char * my_ptr = 0;

Why? This is a personal style and not mandatory.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #28

P: n/a
In message <87************@keizer.soze.com>, Stefan Arentz
<st***********@gmail.com> writes
"John Harrison" <jo*************@hotmail.com> writes:

...
Simple use a class with a destructor (it's because Java doesn't have
destructors that it needs finally)

void Foo()
{
FooBusiness biz;
// Do your foo business that could throw a FooException
}

The FooBusiness destructor does the cleanup. This way you do not even need a
try/catch
I don't buy this for two reasons.

Wrapper classes introduce more code. I would like to use less code. I also
think it is a workaround and not a structural solution.

The above would simply move the exception handling and my finally problem
to a different place but it would still be present.


No, there _is_ no exception handling code. Your destructor just
contains the normal cleanup code that you'd need anywhere.
I like it that you as
a user of the class don't have to deal with it anymore, but that is more
visual/convenience.

S.


--
Richard Herring
Jul 22 '05 #29

P: n/a

"Stefan Arentz" <st***********@gmail.com> skrev i en meddelelse
news:87************@keizer.soze.com...
"Peter Koch Larsen" <pk*****@mailme.dk> writes:

...
I'm on a device that is too small to even include STL :)

S.


I do not understand what you're saying. STL - or templates - does not
necessarily use more ressources than handwritten code. In your case it
should be safe.


Templates, yes probably. But including a 700K library in the firmware is
simply not an option.

S.


700K? What do you mean? I really would like to know how you get these
numbers. The stuff that could take up some space is iostreams - if there is
a lot of locale support, but you could skip that or trim it. Apart from that
you should be in the clear.

/Peter
Jul 22 '05 #30

P: n/a
Stefan Arentz wrote:
Neh, we keep the beer in the fridge. The device is a MIPS based device
with not too much RAM/Flash. Think <= 8MB. which needs to be shared
with a kernel, libraries some tools.

It is not very special, you just can't use all nice tricks that are
obvious on a normal 1GB workstation with a standard 80GB drive :)

8MB? C++ programs can execute in DOS systems with <= 640 KB RAM. And
that is too much too.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #31

P: n/a

"Ioannis Vranos" <iv*@guesswh.at.grad.com> wrote in message
news:ci**********@ulysses.noc.ntua.gr...
Dietmar Kuehl wrote:
Object should always be initialized, i.e. the above line shall be
replaced
by something like this if used at all:

| char * my_ptr = 0;

Why? This is a personal style and not mandatory.


It is "mandatory" if you want exception safe code. The above, without "=0"
is equivalent to:

char* my_ptr = rand();

What happens if/when new throws?

Jeff F
Jul 22 '05 #32

P: n/a
Ioannis Vranos wrote:
Dietmar Kuehl wrote:
Object should always be initialized, i.e. the above line shall be
replaced by something like this if used at all:

| char * my_ptr = 0;

Why? This is a personal style and not mandatory.


Correct, it is not mandatory. However, this "personal" style
reduces the potential for errors dramatically (not only in C++).
It also makes certain, IMO ill-advised, programming approachs,
like e.g. use of "try"-blocks, quite inattractive :-)
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.contendix.com> - Software Development & Consulting

Jul 22 '05 #33

P: n/a
Jeff Flinn wrote:
It is "mandatory" if you want exception safe code. The above, without "=0"
is equivalent to:

char* my_ptr = rand();

Not exactly, but anyway.

What happens if/when new throws?

What happens?

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #34

P: n/a
Dietmar Kuehl wrote:
Correct, it is not mandatory. However, this "personal" style
reduces the potential for errors dramatically (not only in C++).

As I have told many times in clc++, not really.
It also makes certain, IMO ill-advised, programming approachs,
like e.g. use of "try"-blocks, quite inattractive :-)

May you expand on that?

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #35

P: n/a
Niels Dybdahl wrote:
Cleanup code are not part of the program logic, so it is very nice to avoid it in the middle of the main code by putting it away in a destructor.
In addition the destructor approach prevents programmers from forgetting
cleanup code which leads to more stable applications.
So it is not a workaround but a significant improvement.


Totally.

Designs should not duplicate behaviors. If two functions have the same lines
in their finally blocks, they duplicate those lines. Moving these to a
non-deterministic destructor simplifies the design.

Java's reason to exist is C++ memory leaks. Then they solved the wrong
problem. Non-deterministic destructors cause all kinds of trouble, leading
to klutzy work-arounds.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces
Jul 22 '05 #36

P: n/a
Ioannis Vranos <iv*@guesswh.at.grad.com> writes:
Stefan Arentz wrote:
Neh, we keep the beer in the fridge. The device is a MIPS based device
with not too much RAM/Flash. Think <= 8MB. which needs to be shared
with a kernel, libraries some tools.
It is not very special, you just can't use all nice tricks that are
obvious on a normal 1GB workstation with a standard 80GB drive :)

8MB? C++ programs can execute in DOS systems with <= 640 KB RAM. And
that is too much too.


Yes, you can run C++ programs on a AVR with 16K flash too, but that is
not the point.

Sorry but no more smart ass answers on this one please. I *know* what
kind of memory constraints I have in my project.

S.
Jul 22 '05 #37

P: n/a

"Stefan Arentz" <st***********@gmail.com> wrote in message
news:87************@keizer.soze.com...
"Jeff Flinn" <NO****@nowhere.com> writes:
"Stefan Arentz" <st***********@gmail.com> wrote in message
news:87************@keizer.soze.com...
Tom Widmer <to********@hotmail.com> writes:

> On 21 Sep 2004 14:32:39 +0200, Stefan Arentz <st***********@gmail.com> > wrote:
>
> >
> >I was just reading through some old articles in the 'Why not develop
new
> >language' thread and came across the finally debate.
> >
> >Everytime I mention 'finally' to C++ programmers I get almost
emotional > >responses about why it is not needed in C++. I don't get that.
> >
> >For example, consider the following code. Please note, I can only use > >heap allocated objects in my current project (new/delete).
>
> So your current project isn't in standard C++, but rather a
> company/personal dialect? I'm not sure we can help much with that...

Well, it is code for firmware of a small device. Not very small, but small enough that something like STL or Boost is not an option. Templates probably

Is this because your compiler doesn't support STL/Boost? Or that you

"think" STL\Boost will require more memory?


It is because both memory and flash is sparse. And I know for a fact that

it does not fit.


Please adequately define "it"?

In the context of using std facilities in lieu of "finally", you'd only use
boost::scoped_array_ptr, or just use std::vector. With an optimizing
compiler, the size differences should be insignificant. Or by chance are you
looking at debug mode builds?

Jeff F
Jul 22 '05 #38

P: n/a
On 21 Sep 2004 16:03:38 +0200, Stefan Arentz <st***********@gmail.com>
wrote:
where the foo business uses stack based objects whose destructors do
the cleanup. If your company doesn't allow that, then your company is
using mackled C++, and might be better off with C# or Java. At the
very least you can use std::auto_ptr.
So that would mean stack based objects and references? Get rid of all
pointers?


Rather, make sure any pointers are controlled by objects.

It would probably mean a complete redesign of some things,but I am willing to look into it. Is this the RAII stuff other people
were talking about?


Yes. Basically, rather than:

Foo* f = 0;
try
{
f = new Foo();
f->bar();
}
catch(...)
{
delete f;
throw;
}
delete f;
You would do:
Foo f;
f.bar();

or, if necessary,

std::auto_ptr<Foo> f(new Foo);
f->bar();
Tom
Jul 22 '05 #39

P: n/a
red floyd wrote:
Rolf Magnus wrote:

That's what std::auto_ptr is for:

void bar()
{
try
{
SomeObject instace;
std::auto_ptr<char> my_ptr(new char[987]);
// do something
instace.doSomehting() // throws an exception let's say MyExec
}
catch(MyExec &exc)
{
// error handling
}
}


That's double-plus-ungood Rolf. As I understand it, std::auto_ptr<>'s
destructor calls delete, not delete[]. So you invoked UB.


Yes, I realized that after posting. I cancelled the posting, but it seems it
was too late already. Anyway, you could still write some auto_ptr
equivalent for arrays, or use something from boost. Imho, an auto_ptr for
arrays should be part of the standard library.
Jul 22 '05 #40

P: n/a
Ioannis Vranos <iv*@guesswh.at.grad.com> wrote in
news:ci**********@ulysses.noc.ntua.gr:
Jeff Flinn wrote:
It is "mandatory" if you want exception safe code. The above, without
"=0" is equivalent to:

char* my_ptr = rand();

Not exactly, but anyway.


Close enough.....
What happens if/when new throws?


What happens?


How about later in the catch block where my_ptr is attempted to be deleted?
If the variable is initialized to 0 first, then the catch block will be
able to delete it. Without the initialization, the delete would be
performed on an uninitialized pointer, resulting in UB.
Jul 22 '05 #41

P: n/a
> Well, it is code for firmware of a small device. Not very small, but small
enough that something like STL or Boost is not an option.


Not "all" Boost. Just look at the "scoped" smart pointers - two header
files. They are small, efficient, and any decent compiler will
optimize away all the overhead of using them.

BTW, long time ago I missed "finally" just as you do. Now, I consider
it a flaw in a programming language :)
Jul 22 '05 #42

P: n/a
Andre Kostur wrote:
How about later in the catch block where my_ptr is attempted to be deleted?
If the variable is initialized to 0 first, then the catch block will be
able to delete it. Without the initialization, the delete would be
performed on an uninitialized pointer, resulting in UB.

I assume, you mean that you perform many new operations in a large try
block with one catch (std::bad_alloc) for all of them.

Too messy approach anyway.
What about definition upon use like:
char *p=new char[30];
// ...

char *something=new char[40];
In this case you can't make assumptions what has already been allocated
or not.

Both approaches above are not preferable. The best one is use a standard
library container on the stack when you want many objects and an object
alone in the stack if you want one object.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #43

P: n/a
Rolf Magnus wrote:
Imho, an auto_ptr for
arrays should be part of the standard library.


Agreed. There should be something like std::auto_array<>, with
essentially identical semantics to auto_ptr, but using delete[] instead
of delete.
Jul 22 '05 #44

P: n/a
Rolf Magnus wrote:
Imho, an auto_ptr for
arrays should be part of the standard library.


I guess that the Committee decided that that the auto_ptr for arrays is
std::vector.
Jul 22 '05 #45

P: n/a
Ioannis Vranos <iv*@guesswh.at.grad.com> wrote in
news:ci**********@ulysses.noc.ntua.gr:
Andre Kostur wrote:
How about later in the catch block where my_ptr is attempted to be
deleted? If the variable is initialized to 0 first, then the catch
block will be able to delete it. Without the initialization, the
delete would be performed on an uninitialized pointer, resulting in
UB.

I assume, you mean that you perform many new operations in a large try
block with one catch (std::bad_alloc) for all of them.


.... or just one.
Too messy approach anyway.
Granted, we are assuming operations on plain pointers. Smart pointers
would probably be preferable. Helps to hide away this sort of
complexity.
What about definition upon use like:
char *p=new char[30];
Not exception safe (in the total context). Rewrite to:

char * p = 0;

p = new char[30];
// ...

char *something=new char[40];
Same here.
In this case you can't make assumptions what has already been
allocated or not.
With the appropriate re-writes, you don't care. You would only need:

catch( /* whatever */ )
{
delete[] something;
delete[] p;
}

Since in both cases, the pointers are initialized to 0 first (a nothrow
operation), whether the first new failed or the second new failed, it
doesn't matter. The pointers will either be a valid pointer (becuase the
new succeeded), or 0. In either case, calling delete[] on the pointer is
safe.
Both approaches above are not preferable. The best one is use a
standard library container on the stack when you want many objects and
an object alone in the stack if you want one object.


Not necessarily, as you may not have the stack space available to spare,
so heap allocations may be required. Or, there may be a requirement that
the objects be allocated in shared memory somewhere.
Jul 22 '05 #46

P: n/a
red floyd wrote:
Rolf Magnus wrote:

> Imho, an auto_ptr for
arrays should be part of the standard library.


I guess that the Committee decided that that the auto_ptr for arrays is
std::vector.


At one time std::vector did not need to guarantee that its controlled
objects were contiguous - hence inside an array. I don't know what loopholes
or changes have emerged since the Standard came out.

(However, semantically, you should only use arrays at an interface that
requires contiguity, and vector for everything else...)

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces

Jul 22 '05 #47

P: n/a
Phlip wrote:
At one time std::vector did not need to guarantee that its controlled
objects were contiguous - hence inside an array. I don't know what loopholes
or changes have emerged since the Standard came out.

(However, semantically, you should only use arrays at an interface that
requires contiguity, and vector for everything else...)

Yes, although there is such a guarantee now. However prior to that, you
could still use iterators and operator[] to have a "sequential" access,
as with the rest containers.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #48

P: n/a
Ioannis Vranos wrote:
Dietmar Kuehl wrote:
Correct, it is not mandatory. However, this "personal" style
reduces the potential for errors dramatically (not only in C++). As I have told many times in clc++, not really.
Well for starters, it would in the original code (corrected to
use appropriate delete operators):

char***my_ptr;
// at this point, my_ptr contains a random value
**try
**{
****my_ptr*=*new*char[987]; // if this new throws...
// other stuff
****delete[] my_ptr
**}
**catch(MyExec*&exc)
**{
// clean-up
****delete[]*my_ptr; // this expression is undefined
** // error handling goes here
}

Especially in the presence of hard to predict execution paths
uninitialized variables are hard to handle.
It also makes certain, IMO ill-advised, programming approachs,
like e.g. use of "try"-blocks, quite inattractive :-)

May you expand on that?


In general, it is easier to initialize a variable just once rather
than to assign it and later just change it without having read the
value. After all, the initialization would be wasted. If you attempt
to fold initialization with the assignment, i.e. initialize the
variable with the final value, in the above case with the value
returned from 'new', you will realize that you cannot do so prior to
the try-block (after all, it can throw and you want to handle the
error) nor within the try-block because you need the variable to do
the clean-up. The only viable approach becomes the use of a resource
management class - a good think, IMO.
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.contendix.com> - Software Development & Consulting
Jul 22 '05 #49

P: n/a
Stefan Arentz <st***********@gmail.com> wrote:
"Gernot Frisch" <Me@Privacy.net> writes:

I'm on a device that is too small to even include STL :)

The device is a MIPS based device
with not too much RAM/Flash. Think <= 8MB. which needs to be shared
with a kernel, libraries some tools.


8MB ?! Here I was debating whether to use C++ (with STL) in a
device with 128K ram and 256K flash. Unfortunately the only
available C++ compilers were old, so they would not have proper
standard C++ support, and probably would be bad optimisers.
If the platform supported one of the 'mainstream' C++ compilers
(eg. Gnu, Intel, MS) it would have been a more serious option
(But I probably still would have stuck to C so that the code
could port to other devices which didn't have a good C++ compiler).
Jul 22 '05 #50

54 Replies

This discussion thread is closed

Replies have been disabled for this discussion.