Q: Exceptions and when to use them

J

Jakob Bieling

Hi,

somehow the prejudice of exceptions being rather slow (compared to,
ie. returning an error value and checking that) keeps sticking around ..
at least around me. I guess this is also why I refrained from using them
often. But are they 'slow' in general?

I guess it also depends on how, when and where you use them. What I
am looking for is a sort of guideline that explains where exceptions are
approriate and where they are not. The name 'exception' implies to me,
that you should not use them to notify the caller of 'warnings', but use
return values for that kind of 'error' instead. But this is rather just
a guess, which is why I am posting here, to hear your advice.

With this post, I am not trying to ditch exceptions. I do not know
much about their use, so please excuse wording, that might sound
flame-ish.

Thank you!
 
P

Puppet_Sock

Jakob Bieling wrote:
[snip, re: exceptions]
I guess it also depends on how, when and where you use them.

You throw an exception when the promises the interface
makes cannot be kept.

So, that implies that the interface has to make promises,
has to have its required inputs and promised outputs made
explicit. One term for this is "programming to a contract."
Each function will have requirements for what it can accept
as inputs, and make promises about the side effects it
can produce and the values it can return.

This does not tell you enough to design good functions.
But it gives you an idea how to correctly implement
exceptions when you do have good functions.

Basically, stuff that is normal, predictable behaviour
for a function, probably should be handled through the
regular interface. Stuff that is not that may be better
as an exception. That way, you handle the routine stuff
in the interface, and deal with it in client code as
routine stuff. The rare stuff, or the weird stuff, you
handle through the exception mechanism.

In one of the "standard references" everybody recomends,
there's a story about sending somebody to cut the lawn.
And there's various things that could happend.
- He could find the lawnmower, and cut the lawn. Return
message is "yes, ok, done."
- The lawnmower could be out of fuel. So, he has to fill
it and then go on. Should be the same result. And it's
an ordinary occurence. Shouldn't be an exception.
The guy should handle it inside his task. So, he might
have a "cut the lawn" task that includes "check for fuel"
and "fill with fuel" as sub-tasks.
- It could be bucketing down rain, and so cutting the lawn
could be impossible. Result: Return the message "can't
cut the lawn right now, try later." Probably you want
to include this as part of the task, as it's a fairly
regular occurence. So it would go through the regular
interface.
- The lawnmower could be in the garage, the garage could
be locked. What now? Not the ordinary thing, so got to
go get the person with the keys and do something unusual.
That might be an exception, as the keys might be someplace
that is not easily available.
- The lawnmower could be missing. (Borrowed, stolen, not put
back in the right place, etc.) Again, this is outside the
ordinary nature of the task, so it's an exception.

So you get the notion of "ordinary part of the task" and
"not ordinary part of the task." And it depends on context.
Socks
 
I

Ian

Jakob said:
Hi,

somehow the prejudice of exceptions being rather slow (compared to,
ie. returning an error value and checking that) keeps sticking around ..
at least around me. I guess this is also why I refrained from using them
often. But are they 'slow' in general?
Provided you only use them for genuine exception conditions (well
illustrated in the post form "Socks") they shouldn't be slower and in
some case may be quicker and lead to clearer code. You may run into
issues with some compilers (one I have to use consumes ridiculous
amounts of stack with exceptions).

You can reasonably expect throwing and catching an exception to be
relatively expensive.

Try a simple example in your environment:

int f() { return 0; }

int main()
{
<start a timer>
for( unsigned n = 0; n < someBigNumber; ++n )
{
if( 0 != f() )
{
<print error>
}
}
<check time>
<start a timer>
for( unsigned n = 0; n < someBigNumber; ++n )
{
try
{
f();
}
catch(...)
{
<print error>
}
}
<check time>
}

Ian
 
P

Peter Julian

Jakob Bieling said:
Hi,

somehow the prejudice of exceptions being rather slow (compared to,
ie. returning an error value and checking that) keeps sticking around ..
at least around me. I guess this is also why I refrained from using them
often. But are they 'slow' in general?

Well yes, they are slow since they imply a try-catch block and a partial
stack unwind upon a thrown exception. However, when exceptions are used for
what they are meant for (i.e: exceptional conditions for exceptional
circumstances) their performance and the flexibility they provide is hard to
do without.
I guess it also depends on how, when and where you use them. What I
am looking for is a sort of guideline that explains where exceptions are
approriate and where they are not. The name 'exception' implies to me,
that you should not use them to notify the caller of 'warnings', but use
return values for that kind of 'error' instead. But this is rather just
a guess, which is why I am posting here, to hear your advice.

With this post, I am not trying to ditch exceptions. I do not know
much about their use, so please excuse wording, that might sound
flame-ish.

You won't be chastised for ditching exceptions, lol. To those that say that
exceptions shouldn't be used to change a normal program's sequence, i'ld
agree.

But exceptions lets you throw an object which includes diagnostic
information about the error that just occured (thats priceless). This
implies much (you can attempt recovery, log the error, display the error,
throw another Exception, prompt the user, etc). Basicly, at that point where
the thrown exception was caught, you are still dealing with an application
that is potentially recoverable (that too is priceless).

As a simple example, here is a file reader with a diagnostic error reporting
mechanism.
Change the file name to trigger the exception and display the catch-block's
e.what()'s output. You could just as easily wrap the try-catch block in a
do-while loop prompting the user to correct the anomaly displayed and
try-again or quit. Beats generating an exit-return upon the exceptional
condition.

// freader.cpp
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <stdexcept>

int main()
{
std::ifstream ifs;
std::string s_buffer;
std::vector<std::string> vs;
try
{
ifs.open("freader.cpp");
if (!ifs)
{
throw std::exception("(!ifs) while opening file.");
}

while (std::getline(ifs, s_buffer)) // getline until failure
{
vs.push_back(s_buffer);
}

if (!ifs.eof()) // if failure was not an eof marker, throw
{
throw std::exception("(!ifs.eof()) while reading file.");
}

typedef std::vector<std::string>::iterator VITER;
for (VITER it = vs.begin(); it != vs.end(); ++it)
{
std::cout << *it << std::endl;
}
} // end of try block
catch (const std::exception& e)
{
std::cout << "Error !!\n" << e.what() << "\n";
} // catch

return 0;
}
 
P

Peter Koch Larsen

Jakob Bieling said:
Hi,

somehow the prejudice of exceptions being rather slow (compared to, ie.
returning an error value and checking that) keeps sticking around .. at
least around me. I guess this is also why I refrained from using them
often. But are they 'slow' in general?

That depends on how they are implemented. On e.g. Microsofts 32-bit
compilers and GCC on Windows, there is some overhead, but it is quite
possible to implement exceptions with no cost whatsoever if you do not throw
them. So far as I know, gcc on Linux have implemented them this way. Notice
that in this case using exceptions is faster then checking return-codes.
What matters more is that the codes written using exceptions is usually
clearer than code not using them: the main path contain
I guess it also depends on how, when and where you use them. What I am
looking for is a sort of guideline that explains where exceptions are
approriate and where they are not. The name 'exception' implies to me,
that you should not use them to notify the caller of 'warnings', but use
return values for that kind of 'error' instead. But this is rather just a
guess, which is why I am posting here, to hear your advice.

Use exceptions in cases where you encounter an error you can't handle and
which you do not expect to be handled by the code that immediately calls
you. For errors that you expect to be handled by your immediate caller, use
a status code instead (if this is possible).
This is a matter of judgement of course, and in cases where you are in
doubt, you might supply two functions - one that guarantees succes and one
that assumes the caller will check the value.

/Peter
 
R

Rolf Magnus

Peter said:
That depends on how they are implemented. On e.g. Microsofts 32-bit
compilers and GCC on Windows, there is some overhead, but it is quite
possible to implement exceptions with no cost whatsoever if you do not
throw them. So far as I know, gcc on Linux have implemented them this way.

I'm wondering whether that's actually true. Maybe no additional code gets
executed as long as no exception is thrown, but still there is a lot of
additional code needed for stack unwinding in the case an exception is
thrown. This seems to significantly enlarge the total code size, which in
turn lowers the cache effectiveness. And cache misses tend to be very
expensive on modern 32/64bit platforms.
 
P

Peter Koch Larsen

Rolf Magnus said:
I'm wondering whether that's actually true. Maybe no additional code gets
executed as long as no exception is thrown, but still there is a lot of
additional code needed for stack unwinding in the case an exception is
thrown. This seems to significantly enlarge the total code size, which in
turn lowers the cache effectiveness. And cache misses tend to be very
expensive on modern 32/64bit platforms.
First, I have no actual experience with gcc: my information is from this
group (or its moderated cousin). With this reservation I believe my
statement is accurate.
I do not understand your questioning of cache-effectiveness. So long as the
exceptions are not made, they need not be part of the cache. Also, my
understanding is that they will not - exception related code is "put away"
to avoid this. Of course if an exception is actually thrown, it is going to
be costly to unwind - but if this is a rare case it should not matter.

/Peter
 
L

Lionel B

Peter said:
That depends on how they are implemented. On e.g. Microsofts 32-bit
compilers and GCC on Windows, there is some overhead,

FWIW, some months ago I experimented with this (GCC 3.3.3, MinGW port on Windows) for a speed-critical maths library.
The conclusion was that - for my particular code - compiling with exceptions enabled roughly doubled execution time
_even if there was no exception throwing/catching code present_. I've not retested with newer versions of GCC, nor with
other compilers.
 
H

Hang Dog

Lionel said:
FWIW, some months ago I experimented with this (GCC 3.3.3, MinGW port on Windows) for a speed-critical maths library.
The conclusion was that - for my particular code - compiling with exceptions enabled roughly doubled execution time
_even if there was no exception throwing/catching code present_. I've not retested with newer versions of GCC, nor with
other compilers.

I've noticed a 5x speed degradation in some some benchmark tests, but it
does seem to be compiler dependent and with GCC the results varied
wildly from release to release.
 
P

Peter Koch Larsen

Hang Dog said:
I've noticed a 5x speed degradation in some some benchmark tests, but it
does seem to be compiler dependent and with GCC the results varied wildly
from release to release.
So far as I know, it is only the gcc version on Linuz that generates the
"no-overhead" exception code. I do not know why, but it probably is related
to the way the Windows "structured exception handling" is integrated.

/Peter
 
L

Lionel B

Peter said:
[...]

So far as I know, it is only the gcc version on Linuz that generates
the "no-overhead" exception code. I do not know why, but it probably
is related to the way the Windows "structured exception handling" is
integrated.

I wonder... why would g++ have to integrate Windows SEH at all? I suppose it might conceivably afford an effcient
low-level mechanism for implementing C++ exceptions. Can't think why else it might be relevant.
 

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

Forum statistics

Threads
474,138
Messages
2,570,803
Members
47,349
Latest member
jojonoy597

Latest Threads

Top