Exceptions, Go to Hell!

Ö

Öö Tiib

That isn't the topic of this sub-thread. it all started with

"Assertions ("bug catchers" if you will) can be mapped to exceptions for
a release build to facilitate reporting to the developer, for example."

Which unfortunately got snipped.

My argument is that this is seldom, if ever a good idea because the
context of the exception is lost and unwinding can do more damage.

Sorry, then i misunderstood. Yes i agree with you. Especially in
release build? Maybe there is some sort of platform weakness/
peculiarity. Like ... some platform that reboots on assert? You can
usually create a process from other process that can facilitates crash-
reporting and also keeps a backup ready that replaces the crashed
process. Maybe for testing ... like an unit-test that detects
assertions being there?
 
J

jacob navia

Le 24/08/10 08:38, thomas a écrit :
Hi,

Sometimes I found it very convenient to use STL in my application.

But one thing I hate is that STL containers throw exceptions. Because
we handle errors explictly in our application, we don't want
exceptions.

I want to know whether there's any possibility to turn exceptions off,
just like the "new(std::nothrow)" option.

Specifically, will the following operation throw exceptions? How to
handle it without the "try, catch" clause?
-------------
char *p;
string str(p, 20);
-----------

(Don't teach me the benefits of exceptions)

--tom

I am currently developing a container library in C. Since C doesn't
support exceptions, maybe people here can be interested in a different
approach to exceptions and error handling.

The basic design is that each container function (method in the C++
terminology) calls a function if an error occurs. This function call is
the result of a lookup of several "stages":

(1) Each container contains a special "ErrorFunction" field that can be
set by the user after the container is created. This field contains a
function pointer to the function that will be called in case of an
error. This field is initialized by default to the default error
function by the creation procedure

(2) The library has a default error interface for errors that happen
during the creation function. This default error interface can also be
changed dynamically by the user at any time.

If the function call returns, the container returns an error code in
most cases or NULL if there is a single return value.

To obtain a behavior similar to C++ exceptions it suffices to set a jump
context with setjmp and store it in some global. If an error occurs, the
error function just jumps into the recovery context.

The default error function prints the error in standard error and returns 0.
 
J

joe

jacob said:
Le 24/08/10 08:38, thomas a écrit :

I am currently developing a container library in C. Since C doesn't
support exceptions, maybe people here can be interested in a different
approach to exceptions and error handling.

The basic design is that each container function (method in the C++
terminology) calls a function if an error occurs. This function call
is the result of a lookup of several "stages":

(1) Each container contains a special "ErrorFunction"

Too much space overhead considering that containers are the low level
(one step above primitives): 4 bytes (32-bit platform) or 8 bytes (64-bit
platform). Consider that one may want to create a hash table and use the
list container for the bucket chains. It just doesn't "feel" right have
all those 8-byte pointers (64-bit is coming on strong in the desktop
world.. who buys a new computer with a 32-bit OS anymore?) all over the
place, especially since they are not there for mainline purposes (!).
field that can be set by the user after the container is created.

I think you should consider per library error handling rather than per
container. "library" may mean "tree container library" rather than "every
container under the sun library" depending on how you are able to
architect things.
This field contains a
function pointer to the function that will be called in case of an
error. This field is initialized by default to the default error
function by the creation procedure

(2) The library has a default error interface for errors that happen
during the creation function. This default error interface can also be
changed dynamically by the user at any time.

If the function call returns, the container returns an error code in
most cases or NULL if there is a single return value.

To obtain a behavior similar to C++ exceptions it suffices to set a
jump context with setjmp and store it in some global. If an error
occurs, the error function just jumps into the recovery context.

The setjmp/longjmp "exception" libraries are many and decidely
undesireable because setjmp/longjmp are not portable. (What it would take
to make them portable however, I don't know). setjmp/longjmp are
definitely C and definitely not C++ (de facto).

All said, the above kind of stuff is for C. The problem is solved in C++.
C containers are great for C, until they try to look like C++ containers.
There's a line of demarcation in there somewhere (of which when one
crosses it, it is best to write it in C++ rather than C).
 
J

jacob navia

Le 28/08/10 22:52, joe a écrit :
jacob navia wrote:

Too much space overhead considering that containers are the low level
(one step above primitives): 4 bytes (32-bit platform) or 8 bytes (64-bit
platform). Consider that one may want to create a hash table and use the
list container for the bucket chains. It just doesn't "feel" right have
all those 8-byte pointers (64-bit is coming on strong in the desktop
world.. who buys a new computer with a 32-bit OS anymore?) all over the
place, especially since they are not there for mainline purposes (!).

Excuse me but that is a very strange argument considering that C++
exception handling is a great consumer of space! The extremely detailed
tables that the compiler must emit for each function and for each scope
(including those functions that do NOT use exception handling) can take
up to 5-15% of the code size in many applications [1]. THAT is a space
problem that nowadays is taken for granted. Comparing those huge tables
to a single 8 byte pointer in each container is... well, let's forget
it. :)

I think you should consider per library error handling rather than per
container.

This is done automatically. The creation function (constructor in C++)
initializes the error handler of each container with the default error
handler stored in the library wide error interface. In most cases you
should just replace the library wide error handler with your error
function and you are all set. ALl containers will automatically use your
function since at creation time the global error handler is copied in
each container.

This design allows for customization of each individual container error
handler, what is not possible in C++. (As far as I know, please correct
me if I am wrong, I am not a C++ expert)

"library" may mean "tree container library" rather than "every
container under the sun library" depending on how you are able to
architect things.

see above.
The setjmp/longjmp "exception" libraries are many and decidely
undesireable because setjmp/longjmp are not portable. (What it would take
to make them portable however, I don't know). setjmp/longjmp are
definitely C and definitely not C++ (de facto).

The setjmp and longjmp functions are part of the C standard library and
are supported in all C implementations with the same semantics without
any exceptions.

In some environments, C++ compilers use inlined versions of
setjmp/longjmp for C++ exception handling. Specifically Cygwin g++
for instance.
All said, the above kind of stuff is for C. The problem is solved in C++.
C containers are great for C, until they try to look like C++ containers.

Yes, that is why I do not try to look like C++ containers but as C
containers.

The code can be downloaded for free from:

http://www.cs.virginia.edu/~lcc-win32/container.html

Full documentation is included.

---------------------------------
References:

[1]
http://stackoverflow.com/questions/691168/how-much-footprint-does-c-exception-handling-add
<quote>
The size complexity overhead isn't easily quantifiable but Eckel states
an average of 5 and 15 percent. This will depend on the size of your
exception handling code in ratio to the size of your application code.
If your program is small then exceptions will be a large part of the
binary.
<end quote>

The figure of 10% is confirmed in

choices.cs.uiuc.edu/exceptions.pdf
 
J

James Kanze

I don't agree with those definitions, and they seem a bit "lofty".

They sound rather "artificial". Maybe specific definitions
introduced locally in order to characterize problems.
"bug/defect", "tomato/tomoto", they mean the same thing to me.
That one tries to get all the bugs out before release doesn't
factor into the definition for me, nor does it make me want
multiple terms based upon the discovery time of the bug.
In C++, "errors" are expected and defined things (though
probably occur rarely) that one can manage with the exception
machinery (or some other facilities, perhaps that which one
built themself). Errors are detectable while bugs are not (but
they can be flushed out by testing and reduced via good coding
practices).

"Errors" are something that occurs but which shouldn't occur (in
an ideal world). Programming errors are made by programmers,
writing the code, and in general, can't be handled in the code
(because the presense of such errors means that we don't know
the current state of the program). Another word (probably
better) for such errors is defects. Other errors (dropped
connections, errors reading files, etc.) may be due to defects
in other equiment connected to the machine, but there's no
reason to abort everything when they occur. Other things, like
insufficient memory, are processed as "errors", since their
impact on the program is very much like that of a defect in
other equipment. And of course, there are user errors. And
hardware errors in the equipment you're running on. (One of the
most difficult errors I ever had to track down was a hardware
design error which resulted in one bit in the generated machine
code changing---about once every three or four hours.)

Before talking about appropriate strategy, I think you have to
rigorously defined what types of errors you're talking about. I
like the term "defects" for errors in the system you deliver (as
opposed to defects or failures in connecting equipment, or user
error), and errors for the rest. But even then, I wouldn't
ignore the fact that a defect in the software is always due to a
human error in the development process. Somebody made a
mistake, and at least to me, a "bug" sounds to impersonal,
random and caused by some external factor, which is not the
case.
 
J

James Kanze

Goran Pusic wrote:

[...]
Hm, I am not so sure about that. It very much depends on how
religiously and locally you handle exceptions. On one extreme
end, you let everything propagate to the top-level and have
one catch-all block. On the other end of the spectrum, you can
handle each exception as early as possible. In the later case,
you will still have a sizable number of catch blocks.

In the later case, you should probably be using return codes,
instead of exceptions?
 
J

James Kanze

Unless the exception somehow preserves the context of the
assertion, it will be worse than useless.

An exception, by definition, modifies state as it propagates up
the stack. It may (and usually will) also take actions, which
if the state of the program is corrupt, may be different from
the expected actions, resulting in further damage. Except in a
few special cases, an assertion failure must result in the
program terminating as quickly as possible, and doing as little
as possible before terminating. Period.

After that, we'd like as much information as possible about the
context when the assertion failure occured. On any reasonable
system, that will also result if the program is immediately
aborted.
 
J

James Kanze

[...]
True, but not really relevant is this context, or is it? Here,
the focus is on exceptions that replace asserts. If your
application suffers from a corrupted stack, you are in UB land
anyway and neither asserts nor exceptions will handle that
gracefully.

Gracefully, no. (By definition, an assertion failure isn't
graceful.) But an assertion failure (an abort) will generally
provide you with more information than exceptions. Of course,
if the stack is truly corrupt, an exception will result in
something like a segment violation or an out of bounds memory
access, which will result in pretty much the same thing as an
abort.
Thus, I don't see how that says anything on the alternative of
reporting the manifestation of a bug via asserts or
exceptions.

The essential difference is that in the case of an assertion
failure, you've not executed the additional code of a stack
walkback, with the possibility of having made things worse.
 
K

Kai-Uwe Bux

James said:
Goran Pusic wrote:
[...]
The number of "other types" of try/catch statements in code is IMO
very, very small. And the bigger the code base, the smaller it is
(compared to said size).
Hm, I am not so sure about that. It very much depends on how
religiously and locally you handle exceptions. On one extreme
end, you let everything propagate to the top-level and have
one catch-all block. On the other end of the spectrum, you can
handle each exception as early as possible. In the later case,
you will still have a sizable number of catch blocks.

In the later case, you should probably be using return codes,
instead of exceptions?

Often, indeed. But I think, there are cases when "as early as possible" is
not "immediately".

Also: when designing a library, you often cannot predict all use cases. If
you settle on signaling errors via return codes, you presuppose that
checking on return is the right thing to do for the client. Sometimes, you
can be sure of that. In other cases, throwing an exception offers some
flexibility to client code. Thus, you may even encounter the situation where
the library designer decided (rationally) that throwing would be better; yet
the client code programmer decides (also rationally) to check immediately
for the thrown exception.


Best

Kai-Uwe Bux
 
K

Kai-Uwe Bux

James said:
Ian said:
On 08/28/10 09:47 AM, joe wrote:
Ian Collins wrote:
[...]
A programmer is free to make his exception classes as
elaborate as he wants to. Attach a stack trace, for
example, if he wants to.
Which is what I said. But no matter how elaborate the
exception is, if the stack is munted, or memory is exhausted
or <insert bad things here> when it is thrown, it is still
worse than useless.
True, but not really relevant is this context, or is it? Here,
the focus is on exceptions that replace asserts. If your
application suffers from a corrupted stack, you are in UB land
anyway and neither asserts nor exceptions will handle that
gracefully.

Gracefully, no. (By definition, an assertion failure isn't
graceful.) But an assertion failure (an abort) will generally
provide you with more information than exceptions. Of course,
if the stack is truly corrupt, an exception will result in
something like a segment violation or an out of bounds memory
access, which will result in pretty much the same thing as an
abort.

Unfortunately, some context got lost:
Assertions ("bug catchers" if you will) can be mapped to exceptions for a
release build to facilitate reporting to the developer, for example.

You are correct in that a core dump will provide more information than an
exception. However, the case under consideration here is when the program
crashes on a computer of a client. In very many cases, that means that no
core dump is generated (because of local settings) or that the user would
not mail it to you. The problem therefore is not "which way of reporting a
bug generates the best information for debugging" but "which way of
reporting a bug ensures or at least makes it likely that useful information
is forwarded to the programmer".

The way I understand Joe's proposition is to consider exceptions as a means
to that end.
The essential difference is that in the case of an assertion
failure, you've not executed the additional code of a stack
walkback, with the possibility of having made things worse.

It would seem likely that a redefinition of the assert() macro should also
be considered: one that makes it really easy for the user to get all
essential information to the programmer. Ideally, it would print a bug
report including a destination e-mail address.


Best

Kai-Uwe Bux
 
J

joe

James said:
They sound rather "artificial". Maybe specific definitions
introduced locally in order to characterize problems.



"Errors" are something that occurs but which shouldn't occur (in
an ideal world).

I wouldn't say "shouldn't". I mean, sure, you don't want the hard disk to
fail, but very many do. I'd prefer a definition of "error" something more
akin to "an error is something you have to contingently plan for".
Programming errors are made by programmers,

Oh, those are bugs, not "errors" (not the way I was using "error" and how
I was specifically trying to make the distinction between exactly that as
compared to those expected things that you have to contingently plan
for).
writing the code, and in general, can't be handled in the code
(because the presense of such errors means that we don't know
the current state of the program).

Repeating what I said can't hurt.
Another word (probably
better) for such errors is defects.

Well, to me that conjures up quality control from the '80s, so I just use
"bug", which is certainly the field's chosen term for such.
Other errors (dropped
connections, errors reading files, etc.) may be due to defects
in other equiment connected to the machine, but there's no
reason to abort everything when they occur.

Now those are examples of "errors" (not "bugs").
Other things, like
insufficient memory, are processed as "errors", since their
impact on the program is very much like that of a defect in
other equipment.

Yes, still "errors" to be planned for.
And of course, there are user errors.

Of course, some users ARE errors! (But I digress). ;)
And
hardware errors in the equipment you're running on. (One of the
most difficult errors I ever had to track down was a hardware
design error which resulted in one bit in the generated machine
code changing---about once every three or four hours.)

How much of the universe a given program/system considers is
application-specific.
Before talking about appropriate strategy, I think you have to
rigorously defined what types of errors you're talking about.

Identification and categorization of errors is indeed one step of a
handful that are needed for a comprehensive error "handling" plan. Before
identification of specific errors though, one needs a good grasp of the
larger scope of where the program/system resides, so in that respect
strategy definitely comes first (top-down, rather than bottom-up). It may
be "taken for granted" in mature organizations/teams/developers, but to
exclude commenting on it would surely leave some thrashing for solution
too long from a bottom-up path.
I
like the term "defects" for errors in the system you deliver (as
opposed to defects or failures in connecting equipment, or user
error), and errors for the rest.

I like "bug", and I think it is the clearest term. It IS a bit more,
shall we say, "direct", though, as in: "I paid money for this buggy
software?! Fix the @#x& bugs!!". Rather then the much more milder term
you suggested that surely would be only spoken by the voice that says,
"Level 4, failed. You have, 2, more lives remaining" (ref: Minute to Win
It).
But even then, I wouldn't
ignore the fact that a defect in the software is always due to a
human error in the development process.

I'm not sure I like that outlook on things! As much as there are many
formal processes and methods and levels, I'd stick out a few bugs and buy
software from the guy who could use a few bucks (obviously not for the
flight control system on the airplane I board, duh). All said, different
domains require different strategies, methods and techniques.
Somebody made a
mistake, and at least to me, a "bug" sounds to impersonal,
random and caused by some external factor, which is not the
case.

Ohhhhh.... I get it now, you think that bugs are always somebody's FAULT.
Eww-k. (I'm gonna leave that there, because I want to say something in
response to it and feel if I don't say anything I will have implicitly
responded to it be not saying anything, even though it may be taken the
wrong way.)
 
J

joe

James said:
Ian said:
On 08/28/10 09:47 AM, joe wrote:
Ian Collins wrote:
[...]
A programmer is free to make his exception classes as
elaborate as he wants to. Attach a stack trace, for
example, if he wants to.
Which is what I said. But no matter how elaborate the
exception is, if the stack is munted, or memory is exhausted
or <insert bad things here> when it is thrown, it is still
worse than useless.
True, but not really relevant is this context, or is it? Here,
the focus is on exceptions that replace asserts. If your
application suffers from a corrupted stack, you are in UB land
anyway and neither asserts nor exceptions will handle that
gracefully.

Gracefully, no. (By definition, an assertion failure isn't
graceful.)

But, by definition, probably better than the consequence of the unknown
that was about to ensue. As in, "He just seems to have driven off the
cliff" vs. "That guardrail saved his life". The man still alive won't be
going back and confronting the guardrail about it's lack of "grace". So,
decidely then (yes?), guardrails do not have to be "graceful".
 
J

joe

Kai-Uwe Bux said:
James said:
Ian Collins wrote:
On 08/28/10 09:47 AM, joe wrote:
Ian Collins wrote:
[...]
A programmer is free to make his exception classes as
elaborate as he wants to. Attach a stack trace, for
example, if he wants to.
Which is what I said. But no matter how elaborate the
exception is, if the stack is munted, or memory is exhausted
or <insert bad things here> when it is thrown, it is still
worse than useless.
True, but not really relevant is this context, or is it? Here,
the focus is on exceptions that replace asserts. If your
application suffers from a corrupted stack, you are in UB land
anyway and neither asserts nor exceptions will handle that
gracefully.

Gracefully, no. (By definition, an assertion failure isn't
graceful.) But an assertion failure (an abort) will generally
provide you with more information than exceptions. Of course,
if the stack is truly corrupt, an exception will result in
something like a segment violation or an out of bounds memory
access, which will result in pretty much the same thing as an
abort.

Unfortunately, some context got lost:
Assertions ("bug catchers" if you will) can be mapped to exceptions
for a release build to facilitate reporting to the developer, for
example.

You are correct in that a core dump will provide more information
than an exception. However, the case under consideration here is when
the program crashes on a computer of a client. In very many cases,
that means that no core dump is generated (because of local settings)
or that the user would not mail it to you. The problem therefore is
not "which way of reporting a bug generates the best information for
debugging" but "which way of reporting a bug ensures or at least
makes it likely that useful information is forwarded to the
programmer".

The way I understand Joe's proposition is to consider exceptions as a
means to that end.

Welllll, probably. I don't do it that way so I wouldn't know. I was under
the impression that some people (those who use exceptions as much as I
use "if" ;)) do it that way. I leave assertions in release code but
change the handling (I've never done the "notify an admin" thing, but I
hope to! As it stands, I LOG assertion failures after a msg to the user
(if there is one) declaring that the world is about to end and to shut
off their computer with the power switch immediately because their
computer is the cause of the end of the world).
It would seem likely that a redefinition of the assert() macro should
also be considered: one that makes it really easy for the user to get
all essential information to the programmer. Ideally, it would print
a bug report including a destination e-mail address.

I didn't consider unwinding when I wrote the "mapping assertions to
exceptions" thing. "Largely", I do consider "exception" to be equivalent
to abort (or wish it to be so) (abort after that which I want to precede
"abort").
 
J

joe

James said:
An exception, by definition, modifies state as it propagates up
the stack. It may (and usually will) also take actions, which
if the state of the program is corrupt, may be different from
the expected actions, resulting in further damage. Except in a
few special cases, an assertion failure must result in the
program terminating as quickly as possible, and doing as little
as possible before terminating. Period.

Yeah. I "missed" that when I posted. Yeah, I'm still resisting
exceptions.
After that, we'd like as much information as possible about the
context when the assertion failure occured.

Is a stack trace "low hanging fruit"? Yeah, yeah.. IDE's... I was doing
it before IDEs and my code is instrumented to produce such, simply.
On any reasonable
system, that will also result if the program is immediately
aborted.

What will?
 
J

joe

James said:
Goran Pusic wrote:
[...]
The number of "other types" of try/catch statements in code is IMO
very, very small. And the bigger the code base, the smaller it is
(compared to said size).
Hm, I am not so sure about that. It very much depends on how
religiously and locally you handle exceptions. On one extreme
end, you let everything propagate to the top-level and have
one catch-all block. On the other end of the spectrum, you can
handle each exception as early as possible. In the later case,
you will still have a sizable number of catch blocks.

In the later case, you should probably be using return codes,
instead of exceptions?

Can't: too "error-prone". Are you suggesting that C++ exceptions are
INDEED for select situations? To be used RARELY? To be AVOIDED? Well
isn't that special. Are you, .. ummm... SATAN?!!? (ref: SNL, church
lady).

(Is humor allowed in here?).
 
J

joe

jacob said:
Le 28/08/10 22:52, joe a écrit :

Excuse me but that is a very strange argument considering that C++
exception handling is a great consumer of space!

I didn't say C++ exceptions were the answer. Oh, you STARTED from there
and are now working your way backwards from there? I get it now. Even
WOPR needed to play tic-tac-toe a zillion times. ;)
Comparing those huge tables to a single 8 byte pointer in each
container is... well, let's forget it. :)

Well, no. "Let's" not forget that you are proposing a function pointer in
each an every container (and a hashtable can be a bunch of list
containers, remember) as a way to handle errors. Back to the drawing
room, agreed?
This is done automatically.

Whoa! Get the pointer out of "my" container, then say "it is done
automatically. You see, we are stuck at your square zero: I rejected your
design, and you want to "move on". Read: "REJECTED" in red ink sideways
placed by an official stamp.
The setjmp and longjmp functions are part of the C standard library
and are supported in all C implementations with the same semantics
without any exceptions.

I wouldn't know, but know enough to avoid them. Don't make me google and
find the failings of setjmp/longjmp (you're supposed to alleviate the
concerns before you suggest them).
In some environments, C++ compilers use inlined versions of
setjmp/longjmp for C++ exception handling. Specifically Cygwin g++
for instance.

To other than JN: is the above an example of "guilding the lily"?
(Seriously, it came to my mind after reading what he wrote above and I
have no idea what the expression means).
Yes, that is why I do not try to look like C++ containers but as C
containers.

But you're doing setjmp/longjmp to mimic exceptions?? I take it that you
are working from C++ and trying to graft it onto C. And the point is
what? C can be C++? JN, I don't get it.

I already know enough: "bizarro pointer" in each container. I've
categorize your "solution" (quotes important). Really, that is all I need
to know to reject it. Is this "it" (the last attempt?). If so, RIP (the
code, not you).
 
I

Ian Collins

James said:
Goran Pusic wrote:
[...]
The number of "other types" of try/catch statements in code is IMO
very, very small. And the bigger the code base, the smaller it is
(compared to said size).
Hm, I am not so sure about that. It very much depends on how
religiously and locally you handle exceptions. On one extreme
end, you let everything propagate to the top-level and have
one catch-all block. On the other end of the spectrum, you can
handle each exception as early as possible. In the later case,
you will still have a sizable number of catch blocks.

In the later case, you should probably be using return codes,
instead of exceptions?

Can't: too "error-prone". Are you suggesting that C++ exceptions are
INDEED for select situations?

They are by definition for exceptional situations.
To be used RARELY? To be AVOIDED?

I'm sure that isn't what James was saying.
Well
isn't that special. Are you, .. ummm... SATAN?!!? (ref: SNL, church
lady).

(Is humor allowed in here?).

Unwise. Judging from your spelling the reference could be a US TV show,
unknown elsewhere!
 
J

jacob navia

Le 29/08/10 06:24, joe a écrit :
Well, no. "Let's" not forget that you are proposing a function pointer in
each an every container (and a hashtable can be a bunch of list
containers, remember) as a way to handle errors. Back to the drawing
room, agreed?

Each container has a pointer, not each element in the container. The
cost of that pointer will be amortized by the number of elements that
the container holds. This is a flexible approach that allows for a fine
control of the behavior in case of an exception.

If we would store a pointer to the error function for all containers, it
would be too coarse for most applications.

Source code for the library is provided and you can modify it as you like.
 
T

Tim H

Le 28/08/10 22:52, joe a écrit :
jacob navia wrote:
Too much space overhead considering that containers are the low level
(one step above primitives): 4 bytes (32-bit platform) or 8 bytes (64-bit
platform). Consider that one may want to create a hash table and use the
list container for the bucket chains. It just doesn't "feel" right have
all those 8-byte pointers (64-bit is coming on strong in the desktop
world.. who buys a new computer with a 32-bit OS anymore?) all over the
place, especially since they are not there for mainline purposes (!).

Excuse me but that is a very strange argument considering that C++
exception handling is a great consumer of space! The extremely detailed
tables that the compiler must emit for each function and for each scope
(including those functions that do NOT use exception handling) can take
up to 5-15% of the code size in many applications [1]. THAT is a space
problem that nowadays is taken for granted. Comparing those huge tables
to a single 8 byte pointer in each container is... well, let's forget
it. :)

I can instantiate thousands or millions of containers (think of that
hash of lists), but I will not have nearly that many function entry
points or active threads.

This is why OO implementations have a single vtable pointer, rather
than N function pointers. If you need a different vtable, subclass.

8bytes isn't a ton, but it is wasteful. If your app reallllllllly
needs that level of granularity, then you have to pay the overhead, I
guess. You could optimize by storing a RLE'd or Huffman coded int
which is an index to a table of error function pointers. I strongly
suspect you don't _actually_ have a unique error handler per instance,
but you like the idea that you COULD.

Tim
 
J

jacob navia

Le 29/08/10 19:32, Tim H a écrit :
Le 28/08/10 22:52, joe a écrit :
jacob navia wrote:
(1) Each container contains a special "ErrorFunction"
Too much space overhead considering that containers are the low level
(one step above primitives): 4 bytes (32-bit platform) or 8 bytes (64-bit
platform). Consider that one may want to create a hash table and use the
list container for the bucket chains. It just doesn't "feel" right have
all those 8-byte pointers (64-bit is coming on strong in the desktop
world.. who buys a new computer with a 32-bit OS anymore?) all over the
place, especially since they are not there for mainline purposes (!).

Excuse me but that is a very strange argument considering that C++
exception handling is a great consumer of space! The extremely detailed
tables that the compiler must emit for each function and for each scope
(including those functions that do NOT use exception handling) can take
up to 5-15% of the code size in many applications [1]. THAT is a space
problem that nowadays is taken for granted. Comparing those huge tables
to a single 8 byte pointer in each container is... well, let's forget
it. :)

I can instantiate thousands or millions of containers (think of that
hash of lists), but I will not have nearly that many function entry
points or active threads.

I suppose that each list has at least 2 elements, ok?

If you build 2 million lists, and each element of that list
is (say) 64 bytes long, you have 2e6*(64+16)*2 in C++. 2 million
times 64 bytes object size, + 16 bytes Next/Previous pointers,
assuming that the list object header takes zero bytes storage.

Total: 320 million bytes storage.

In my setup, you would have an overhead of 2e6*8 bytes more, 16
million bytes, around 5% only. And you will agree that this example
is designed to maximize the consequences of this pointer overhead, that
I assume 8 bytes long (64 bit implementation)
This is why OO implementations have a single vtable pointer, rather
than N function pointers. If you need a different vtable, subclass.

Exactly, all vtables have a single pointer in my implementation too.
This is not specific to C++. I could have stored the error function
pointer in the vtable but then any modifications would modify the
bheavior of all the members of the class and NOT only of a specific one.

8bytes isn't a ton, but it is wasteful. If your app reallllllllly
needs that level of granularity, then you have to pay the overhead, I
guess. You could optimize by storing a RLE'd or Huffman coded int
which is an index to a table of error function pointers. I strongly
suspect you don't _actually_ have a unique error handler per instance,
but you like the idea that you COULD.

Tim

Well, that is a great idea actually. In MOST applications the user will
not bother and use the default error handler.


This discussion about the 8 bytes overhead has taken us away from the
main line of my post:

(1) Store a per instance error handler pointer that the user may subclass.
(2) Call it at any error. If it returns, return an error code.

This has the advantage of eliminating exception handling tables
and providing maximum flexibility.
 

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,756
Messages
2,569,540
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top