The 'finally' debate

A

Andre Kostur

Not exactly, but anyway.

Close enough.....
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.
 
R

Rolf Magnus

red said:
Rolf said:
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.
 
N

Nemanja Trifunovic

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 :)
 
I

Ioannis Vranos

Andre said:
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.
 
A

Andre Kostur

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.
 
R

red floyd

Rolf said:
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.
 
R

red floyd

Rolf said:
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.
 
P

Phlip

red said:
Rolf Magnus wrote:

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...)
 
I

Ioannis Vranos

Phlip said:
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.
 
D

Dietmar Kuehl

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.
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.
 
O

Old Wolf

Stefan Arentz said:
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).
 
D

Dietmar Kuehl

Stefan said:
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 :)

I developed most of my standard C++ library on a machine with 160MB
of disk space (yes, *disk space*, not memory). I had (newer version
of gcc unfortunately broke it) a C++ hello-world which took 4kB
(yes, 4*k*B). I think it is now ~40kB, mostly due to the exception
support I need to include. However, this was in an experimental
branch and not merged into the main library (it was mostly a demo
of what can be done; unfortunately, nobody pays me for actually
doing this to the whole standard C++ library...). With my "normal"
implementation, it indeed takes ~700kB for a hello-world (stripped
executable on an Intel machine).

Anyway, you should realize that STL != "standard C++ library": the
STL is just the generic stuff (containers, iterators, algorithms).
This will have no or at most only very small overhead compared to
manually written code.
 
D

Daniel T.

Stefan Arentz said:
(e-mail address removed) (Alf P. Steinbach) writes:

...


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.

struct Vars {
Vars(): vars() { }
~Vars() {cleanup vars;}
vars;
};

void Foo() {
Vars v;
// do stuff with v.vars;
}

I don't see why you are ignoring the simple and obvious solution...
 
D

Daniel T.

Phlip said:
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...)

AFAIK, std::vector was allways meant to be contiguous.
 
G

Greg Comeau

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).

It's said we have proper standard C++ support, and are always
glad to do custom ports, so feel free to email us.
 
R

Richard Herring

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

But if you actually *need* the strict-ownership move-not-copy semantics
of auto_ptr, it's not. If you don't, then boost::scoped_array is another
possibility.
 
T

Tom Widmer

...


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

You don't need 700k. To use the STL you don't need to link any
libraries at all (assuming your allocator implementation is in the
header). If you've got enough resources to have exceptions enabled,
you've certainly got enough for the STL (which requires exception
support ideally), and
std::auto_ptr/scoped_ptr/scoped_array/std::vector/etc.

Remember, with templates, only code that is actually called gets
compiled into your .exe.

Tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top