Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

I keep running into long term c++ programmers who refuse to use exceptions

113 views
Skip to first unread message

walter...@gmail.com

unread,
Mar 6, 2010, 8:18:00 PM3/6/10
to
{ This article may look like spam at the beginning, and my spam filter thought
so, so if you're not reading this mod comment then that may be the reason. :-)
The article is close to 50 KiB, while our suggested [excess] rejection criterion
is >50 KiB. Please trim excess quoting from responses. -mod }

C++ Exceptions

Nomad: I am Nomad. I am perfect.
Kirk: I am the Kirk, the creator?
Nomad: You are the creator.
Kirk: You are wrong! Jackson Roy Kirk your creator is dead. You have
mistaken me for him. You are in error. You did not discover your
mistake. You have made two errors. You are flawed and imperfect and
have not corrected by sterilization. You have made three errors.
Nomad: Error. Error. Error�.. Kaboom!

Start Trek "The Changeling"

Let us hope that when Stardate 3541.9 rolls around, we will no longer
be "in error". For now, however, computer programs have lots of bugs.
Bugs = wasted time, and thus wasted money. And I mean wasted money,
millions and billions of dollars worth. Some famous computer
catastrophes are available at http://encyclopedia.laborlawtalk.com/Computer_bug.
My personal favorite being the flaw in the Mars Climate Orbiter
software causing the loss of a space probe to Mars that cost 165
million dollars. I love the space program. We computer programmers
can't keep making this type of mistake and maintain credibility. As if
we had any anyway. Many studies are showing that software projects are
failing at an appalling rate http://www.it-cortex.com/Stat_Failure_Rate.htm

What I have found to be the biggest single reason for wasted time and
money at coding time (design and specification failures are much more
costly) is the failure to detect when the program erred. This means
failure to check whether a function, the basic building block of every
computer program, succeeded or not. The second most common problem is
the failure to report an error when it does occur. And an outright
crash is not the worse type of bug because that is reported to the
user. Those happen and can be dealt with. It's the invisible failures
that stay in the program undetected that cripple your program for
years before they are detected. Many of us have had the experience of
going through some old legacy code and saying, "Oh my god! No wonder
this never worked right! Look at this!!!"

Error detection, handling and correction are often never even thought
of, and even in some of the biggest software houses are handled
sloppily. The reason for this is not programmer laziness. It is
because until recently programming languages did not have any
consistent, enforceable methodology for dealing with the unexpected,
with errors. This issue has been resolved by the concept and usage of
exceptions.

I will assume you are familiar with C++ exceptions and have used them
on occasion. If not, you might want to bone up on them:
http://en.wikipedia.org/wiki/Exception_handling

Some smart people thought it wise to include exceptions in the C++
language, and after trying them for about a day I was sold. When a
function fails its task, it invariably affects other parts of the
program. Like a crowded freeway when one car stalls, the entire
freeway jams up. When a function in a program fails, all the functions
that depend on that function are also at risk. Once must recognize
that when a function fails, the entire program enters a different
state. We don't just have an isolated failure. We have an entire new
state of the program that might be called chaos because the unexpected
has happened.

How to properly use C++ exceptions

What I'm going to show you is how to really revolutionize your
programming by using exceptions to make error handling as painless as
may ever be possible.

Exceptions will enable you to remove almost all error handling clutter
from your code, make your code more easily re-useable and much easier
to debug.

The exception mechanism is simple. Anywhere in your code where you
want you can "throw", like this:

throw "An error occurred here";

or

throw 22;

or

throw std::string("This is messed up right up in here.");

You can "throw" any data type you want, even pointers.

At other points in your program you "catch" anything thrown with the
catch() statement which catches anything thrown from within the try
area.

try
{
throw std::string("Ooops I messed up");
}
catch(const std::string& theException) // You have to "catch" the same
type you threw (or a reference to it, and it can be const)
{
//if any exceptions are throw by "do something", we come
here
}

That's it. That's the simple syntax of using exceptions. Though the
syntax is simple, how you use this is ultra powerful.

A simple example of how you might use exceptions:

FILE* FileOpen(const char* filename, const char* mode)
{
FILE* theFile = fopen(filename, mode);
if ( !theFile)
throw "Error opening file";
return theFile;
}

int main(int argc, char* argv[])
{
try
{
FILE* theFile = FileOpen("testfile.txt",
"r");
// Do something with the file
}
catch(const char* error_string)
{
// If FileOpen fails we come immediately
to here, skipping "Do someth ing with the file"
puts(error_string);
exit(-1);
}
exit(0);
}

If FileOpen() fails, it throws an exception which immediately unravels
all functions that were already called within try and executes the
code contained in catch.

C++ provides you this syntax of exceptions. It doesn't tell you how to
use exceptions well. I'll try to provide some help with that.

The first important rule to remember about using exceptions well is
that (with a few exceptions) you should only throw an exception when a
function fails to perform its job. The reason for doing this is part
and parcel of the philosophy for using exceptions and is embedded in
the very name of the concept: exception. Exceptions should be thrown
when the normal, expected flow of your program experiences an oddity,
an exception. What is normally called an error falls into this
category also.

The item thrown can be any class or anything that can be a variable.
For the sake of simplicity, in the examples above I threw a const
char*. For reasons I will get into later you normally want to throw a
class specifically designed to be thrown. Why? Because error
conditions are a sort of problem domain unto themselves and a class
specifically designed to capture information for that domain is best.

The single most important thing to remember about exceptions is the
try/catch system is s imply a way to return, to throw away, an
arbitrary number of stack frames. This means throwing an exception is
like a function return, but the return can span many functions deep
and return anything you want.

This is powerful because now you do not have to add error handling
code everywhere, only where you actually care about doing something
with the error.

That is the simplest, most general and accurate statement that defines
the purpose of C++ exceptions. Why would you want to do this?

To be able to throw away any amount of a program if something fails
because when something fails all the things that depend on that thing
will potentially also fail. This implies that an entire chain of
functions is at risk if any one of them fails. A chain is broken if
any one of its links are broken. If a link breaks, the entire chain
starting at the very first link must be thrown away and that failure
must now be dealt with (in the catch clause).

To recognize that error conditions present their very own peculiar
requirements and due to the importance of errors in computer programs
they need their own syntax and mechanisms to handle them.

First, I recommend you never throw the standard exceptions provided in
your library such as std::runtime_error. This is not because they are
badly written. It is because they are too general, not written for
your program. Let me explain.

Success in Object Oriented Programming is largely based upon creating
and using good components. The exception class you use might possibly
be the most important single class you'll ever use in your programs so
it's really important that it be good, or at least, not initially
flawed because a good class can be subclassed later to add features.
You don't want to use an exception class that has built in limitations
and the standard exceptions have built in limitations, mainly, they
are what they are and you can't change them to suit your application.
If you change them, they are not longer the standard exceptions!

You should create your own exception class subclassed from
std::exception. (In fact there is a general principle here that you
should never use the classes provided by someone else directly because
they will inevitably be lacking in some feature you need later, but a
more complete discussion on that subject I'll have to put off for
another day). For example, here is the simplest Exception class you
can get away with that subclasses from std::exception

#include <exception>

class Exception: public std::exception
{
};

This is a bare minimum but covers your ass by enabling you to retrofit
features later as you come to need them. You could use this in your
program and add more features to it later as they become necessary.

Something more useful would add a message that could be displayed
later when the Exception was caught. Displaying the message should be
done with the what() function because if you are catching
std::exception, which you should be, its what() function is virtual so
that any class derived from std::exception that gets caught will use
its what() due to the magic of virtual functions.

#include <exception>
#include <string>

class Exception: public std::exception
{
std::string Message;

public:
Exception(const std::string& message)
: Message(message)
{
}

const char* what() throw() // throw() required if your
STL std::exception has it.
{
return Message.c_str();
}

~Exception() throw() // Here only to please some
compilers
{
}
};

And there are other good reasons why you need to use your own
exception class. Notice, all of these things are optional. The power
of your exception class depends only how much you choose to add.

Having the source code to your own Exception class, you can put a
breakpoint when debugging and catch any exception in the debugger
right when it happens.

You can write the exception text into a log file to help debugging.

You can add a stack trace to the exception information that greatly
helps debugging

You can look up error detail information and add it to the exception
string to help debugging (i.e. strerror(errno))

Because you have the code, you can retrofit features you find out you
need later, or even subclass again to add more features.

Since you inherit from std::exception your class is an std::exception
and can be cau ght wherever an std::exception is used and so is error
compatible with other code that uses std::exception

You can redirect exception logging anywhere you want by adding the
appropriate code in the Exception constructor, like to syslog for Unix
style programmers or you can help debug a customer problem by having
them send logging over a TCP connection to you from anywhere in the
world.

And in general you can do anything you want when an error occurs by
adding that appropriate code into Exception::Exception.

Once you have this basic exception class you can proceed to using
exceptions. This next section will cover common programming Diseases
and how exceptions cure them.

Problems caused by not using exceptions and how to fix them

Disease: Programmers pathologically ignore or forget to check return
codes from functions and now there are hard to find bugs in the
program.

Until exceptions were invented the popular way to indicate a function
failure was to return an error code, but this method depended upon the
caller checking for the error value. This was more often than not
ignored and thus programs failed seconds or minutes later for
apparently unknown reasons and debugging was very time consuming (i.e.
expensive) because the symptom of the error occurred a long way from
its cause and one had to be a detective to track down the problem.
Using error codes there was no mandatory requirement for the caller to
check the error code. The returner of an error code is really at the
mercy of the caller to ensure the error is dealt with. Experience has
taught that the vast majority of function calls are not checked for
error status leaving a hidden point of failure in your program that is
time consuming and costly to track down when it does fail. It isn't
the common errors that occur a lot that kill you; it's the ones that
occur ran domly and are hard to reproduce that destroy your product.

If you signal an error, i.e. a failure of the function to perform its
task, by throwing an exception, a programmer must deal with it. It
cannot be ignored by accident.

A few macros can really help you nail down ALL error handling:

#define THROW_IF_ERROR(CODE) if ( (CODE) == -1 ) throw
Exception( #CODE ": failed");
#define THROW_IF_NULL(CODE) if ( (CODE) == NULL ) throw
Exception( #CODE ": returned NULL");

Now you can easily retrofit all those old C functions that use old
fashioned error return codes:

THROW_IF_ERROR( printf("Your momma dont dance and your daddy dont rock
and roll") );
THROW_IF_NULL( file_handle = tmpfile());

This makes it easy for programmers to check errors. You must give them
every tool possible to do this if you want good error handling policy
in your project.

Disease: A clean and beautiful algorithm is made obscure by messy
error handling code.

Until exceptions came along, programmers didn't mind adding all kinds
of if statements to their algorithms that had nothing to do with the
algorithm itself; all kinds of "if (error) then (do this)" statements
which themselves are a good source of bugs in a program. Checking
error codes is onerous and fills nicely written functions with error
checking code that contributes nothing to the primary purpose of the
function. You've got a significant portion of the function dedicated
to handling failures, when failures occur in an insignificant
percentage of the time. That is, you've got perhaps 30% of your code
(if you are truly checking each function call for success of failure)
devoted to .001% or less of the actual run time of the function.
Imagine you are walking down the street and every step you take,
having to look down and see if your foot actually made it! If
statements are also murderous on the execution speed of the program
because the processor must throw out of its pipeline any pre fetched
execution path that wasn't taken.

Users of exceptions know that the big negative of using if statements
to check return codes is that you are wasting time even when things
are going well. Exceptions make it so that you only spend time when
things are going wrong.

If your function, calls other functions that themselves throw
exceptions for error handling, you don't have to add any error
handling code in most cases. Most of the time all you are doing is
passing a failure back to a caller higher up the stack. If you are
using exceptions, this is done automatically for you and you need to
add no code at all. In practice, only a few high level functions
actually need to catch exceptions. Functions inherit their error
handling and most don't need explicit error handling code. Unnecessary
because you will find when throwing and catching exceptions, you only
throw where the error actually happens and you only catch where you
want to handle. This is almost always several functions away meaning
all intermediate functions need no error handling at all. They inherit
their error handling.

Using the analogy of walking down the street, you only react if
something out of the ordinary occurs: your foot hits something and
throws an exception up to your knee. Your knee doesn't know how to
handle this so it doesn't catch the exception but allows it to
propagate to your spinal chord which, in the same vein, doesn't know
what do so allows the exception to propagate to your brain which DOES
know what to do. So your brain catches the exception and deals with it
and you don't have to explicitly check each and ever step you take.
You only get alerted if SOMETHING GOES WRONG, NOT IF SOMETHING GOES
RIGHT. The only reason you have to add any throws at all is because
you are talking to old fashioned operating system calls that return
error codes which you have to translate into a throw exception in your
more modern C++ code.

This problem of code intending to do one thing being cluttered with
code doing other stuff is so annoying to programmers that an entire
programming approach has been invented called Aspect Oriented
Programming: http://en.wikipedia.org/wiki/Aspect_Oriented_Programming

Using exceptions is very effective in removing clutter from your
functions as regards error handling code. You won't need Aspect
Oriented Programming to deal with this.

Disease: Indecision and disagreement about how to deal with errors in
a program.

Using return codes to signal errors makes the programmer try to come
up with a return value that makes sense (at the time) but whatever he
picks won't necessarily be the same that someone else decided to use
in the rest of the project. Return code conventions are inconsistent.
For example the Windows API has a wide variety of conflicting and
inconsistent return codes to indicate error. Some functions return
true, others return false, others return an error value, some return
0, some return NULL, some return HRESULTS. The UNIX C functions are
not much better. Over the years programmers have just accepted the
fact that things are this screwed up. This is not a minor issue. Many
bugs can be traced to programmer confusion over return codes and a lot
of programmer time is consumed having to constantly look up what the
function return value means in the documentation. How many of you know
what printf() returns to indicate error? mkdir()? chdir()? stat()?

Also realize the mental energy the programmer wastes by having to make
a stupid, and what he knows is really a useless decision about what
error code to return. When a programmer is limited to return values as
error indicators he has a constant problem while coding.

Programmer's'Brain ->"Here is a place that could fail. What do I do?
Return -1? Return NULL? Return 0? Return an error value? Return false?
Try to recover? How do I clean up what I already had in progress?
Damn, now where was I? What was my function doing?

Ok now I'm using a function someone else wrote. What error does this
function return? Should I check it or just hope for the best? Didn't I
just go through this same thought process the last function I wrote?
Why doesn't someone do something to fix all this wasted time and
energy I spend every time I write a function?"

Exception-using programmers gracefully handle errors using exceptions.
They simply throw Exception when their function cannot fulfill its
task. They don't have to ponder how the caller will handle this. A
program or library that uses exceptions based upon std::exception is
instantly future error compatible with other code using the standard
exceptions so he doesn't have to spend 50% of his brainpower trying to
figure out what to do during errors which are .001% of the instances
of his function being called.

You will also get programmers on a team fighting about this kind of
stuff. That's bad. Having a standard exception class makes it easier
to reach a consensus because exceptions DO work for handling error
conditions so you can reliably order them to do so and be confident
your decision will work out in the end.

Disease: Return codes cannot provide enough information about an error
in order to decide how to handle it.

Return codes report next to nothing about errors. Error reporting done
from error codes is next to useless as far as informing us what the
error is. Error codes can only be a single number and thus can only
display pre-canned system messages such as "no access" or "parameter
failed" when in reality the error should report much, much more such
as "Unable to open file foo.bar due to permission errors, it is not
owned by you" or "Parameter 5 passed to function foo() was 27 which is
out of the allowed range for this parameter". Return code programmers
stay late at work trying to figure out what happened.

Exception users give full and accurate information about their errors.
Exceptions can be any type of object and can report any information
necessary. A nice, well rounded exception message might contain
information like this: Windows Error(10045) Connection Timeout
connecting to www.testpatch.com at location TCPConnect.cpp line 245
which gives you instantly what would take an "error code" programmer a
half hour to gather. Don't waste time figuring out what happened, have
the computer do it for you. That's what it's there for. When you
construct your exception you can have strerror() put the string
version of the system error in the exception.

Disease: An error occurs in a function that cannot return a value.

Some functions cannot return error codes. Constructors, conversion
operators, and operator overload functions cannot return a success or
fail value and thus cannot report a failure using error codes.
Functions that return useful values such as the product of a
multiplication cannot return an error value.

One way programmer work around failed constructors is by having the
constructed object mark itself bad by perhaps a bool Bad data member.
Then check it later and not use it. This is really bad because, if an
essential object fails to construct, the entire function which uses it
must certainly also fail. There is no reason to continue past a failed
constructor but if you aren't using exceptions you must now add all
kinds of if (object-bad) garbage, often bigger in size than the code
of the constructor itself, to handle its failure. You must also
manually deconstruct anything that was constructed in this constructor
and do all the accounting necessary to keep track of what was
constructed and what wasn't.

Using exceptions you simply throw if the constructor fails. Let the
code that attempted to construct this object worry about what to do. C+
+ will automatically destruct any half constructed object for you.

Disease: Return codes corrupt the meaning of the word "function" and
destroy the code's usability as a function

Mathematically speaking, the definition of a function is this: http
http://en.wikipedia.org/wiki/Function_%28mathematics%29. It's
important to note that a function translates multiple inputs into
exactly one output. This means that the "result" of the function is
the output, or in computer science, the return value. Why is this
important? Because it implies that as you expand the functionality of
a program, you can substitute in a "dynamic" value (a function) where
there was once a static value (a simple variable).

For example, you can print someone's name:

Print("Jim Johnson");

Or you can print a transformation of the name more suitable to your
needs.

Print LastNameOnly("Jim Johnson");

The latter line uses a function which, while being handled like a
piece of data, actually computes a changing, dynamic value. The real
power of the computer comes when doing many things with the same basic
pattern, but slightly different details. That's what functions can do
for you. However, functions can fail. They may be unable to compute a
return value for whatever reason. Programmers who use return codes,
destroy the utility of a function by returning a "success" or
"failure" indicator instead of the actual product of the function, in
this case, just the person's last name.

So if all you had available to deal with errors was returning a
"special" value meaning "failure" the above simple code would become
something like this (Here the programmer outputs the result into a
variable he has already declared and uses the return value of the
function as a success or failure indicator).

String LastName;
bool success = LastNameOnly("Jim Johnson", &LastName);
if (success)
Print LastName;
else
DealWithError()

Wow. You've gone from one line of code, to 6, effectively sextupling
the complexity, bug probability and learning time for this code. This
may not seem like much but if you multiply it by the thousands of
functions in a program it becomes quite significant. Instead of a
statement, you now a program snippet that is not understandable at a
glance. 5/6 of that snippet is devoted to error handling for a
situation that might only occur 1 out of a million times in actual
practice (person not having a last name). You are asking every
programmer who ever reads this to spend 5/6 of his brain power
thinking about something that might happen .00001 percent of the time.

Disease: Errors are occurring in the program but where to look in tens
of thousands of lines of code?

Without good exceptions, a programmer would handle it this way: He
tries to guess what is happening and places breakpoints at the places
that he suspects problems are happening. How much time and money do
you want to waste on programmers guessing where to put breakpoints?
There is no single place, object or module where errors get handled.
This means there is no single place the programmer can inspect, log,
measure, set breakpoints or display errors.

If you use a hierarchy of exceptions to signal errors, you know
exactly where, when and how errors are occurring in your program at
all times. How? Because all errors in your program call the base
exception class constructor and there you can log, display, measure
and set breakpoints. In my experience, this is in fact the first
benefit most programmers notice when they start to use exceptions and
one way to convince them to keep using exceptions. It is also a
reason why you never want to use exceptions for trivial reasons. Doing
so would make a constructor breakpoint like this break too often to be
useful.

Disease: Errors are occurring in the program out on customers'
computers off site.

If all you have is return codes and a chaotic error handling system
you have to tell your boss: "I can't debug this unless I can put the
code in a debugger to see what's happening". Error messages are
missing or so incomplete that the user cannot fix the situation nor
can the programmer even understand what is going on remotely.

Users of a full featured exception class use full information in their
errors so that often the error messages are descriptive enough for the
user to fix his problem. Also, since all errors channel through the
same function, the base exception class constructor, you can tell the
user having a problem to turn on the logging and save a trace of the
errors occurring offsite or even have the code send log messages
across The Internet immediately so you can figure out exactly what is
failing!

Disease: Some code is moved to another project and needs to be
integrated into its error handling scheme.

Return coders know this project will be a nightmare. If the new
environment doesn't use the same conventions they did to do error
handling, there will be a lot of rewriting, debugging, testing,
crashes and customer frustration to deal with. Error codes cause the
caller and the callee to have to agree upon a particular set of
conventions, error codes, which makes both inflexible for use in other
situations.

Using exceptions based upon the same standard subclass,
std::exception, makes transferring libraries, classes and programs to
other project completely error compatible. Even if the moved-to
project uses a different exception hierarchy, catch clauses are all
that have to be changed, and they are usually very few in most
programs.

Disease: Hardware errors throw exceptions. Access violations, divide
by zero, stack overflow and other usually fatal conditions are
signaled by exception throws in many operating systems. If you aren't
prepared to deal with exceptions, all your program can do is die
suddenly.

If you are depending on return codes to handle these, too bad. You're
screwed. Operating system will throw up an error message box and exit
the program. Imagine a heart monitor program Access Violating and
simply FAILING without at least notifying the nurse on call that
something is wrong.

Hardware errors are exceptions that can be caught just like any
others. In Unix style OSs you use a signal handler, and in Windows you
use _set_se_translator() to catch hardware exceptions and turn them
into C++ exceptions. Then you can actually do something useful like
print a stack trace to help debug or ring an alarm to ask a human
being to come and help. In many cases if a thread has a hardware error
you can catch it without crashing the entire program. In all cases you
can catch the hardware error and deal with it in your own way instead
of letting your operating system terminate the program.

Disease: The need to signal an error condition in code that has no
provision for dealing with errors because when it was written no one
expected that an error could occur here.

If you are stuck using return codes there is little you can do except
rewrite all the functions involved. Perhaps you can log the error and/
or put up a message box informing the user. Forget about doing
anything to actually handle the error. Retrofitting good error
handling with return codes on already written programs is next to
impossible. When the failing function is 10 levels deep and all the
functions above it already have their return values being used for
other things because the original programmers didn't expect anything
to fail, there is no way to return that error condition up the stack
to someone who can do something about it. In the real world, the
programmer just gives up and hopes the error doesn't occur. Of course
it does, it fails silently and the program behaves strangely and it
takes days to track down what is going wrong with it.

Disease: Error conditions have no consistent strategy for dealing with
them.

Exceptions give error handling its own set of tools more suited to the
conditions error handling has to deal with. Code that uses exceptions
has its own domain especially designed for handling errors.
Retrofitting a new error condition on a program that uses exceptions
to report errors involves very little new coding: just throwing the
exception somewhere, and catching it somewhere else. And often it is
not even necessary to write a new catch clause because an existing one
already does the job. The point is, all you do is throw. The handling
of the error is up to the higher level code which he can look at
later.

Disease: Functions tangled with return code checking, propagate their
problems to anyone else using them, spreading complexity like a
cancer.

If the members of your class know how to copy themselves, then your
class doesn't need a custom copy constructor. The same is true for
many other common functions like constructors, destructors, operator=,
operator== etc. However, if any of those classes don't use exceptions
to signal failures, you cannot rely on these auto-generated functions
and you must write custom versions. A real example from my last job
was a situation where a class had a "File" member. In my class's
constructor initialization list that File class was constructed like
this File("datafile.txt"). However, this File object's constructor was
failing INVISIBLY because it did not use exceptions to signal a
failure (it depended on the programmer to check a "good" variable). It
took us hours to track down what the problem was. This is a clear
example of why you should not rely on return codes even in classes
that you consider trivial. The programmer's excuse in this example was
"that's how the iostream library works". The iostream library, bless
its heart, was written before exceptions were part of the language. I
suggest if you use it, wrapping it in your own classes that do throw
exceptions if failures occur. It's hard to get people to use
exceptions if parts of the standard library do not, but that doesn't
mean they are correct. They aren't exempt from the problems I describe
above but their current state, the state of all "standard" c++
libraries reflects the battle we have going on between old fashioned
programmers who refuse to use exceptions, and those who have seen the
light and do.
-
Disease: Callbacks that offer no way to signal their callers

A common way to operate on items in an STL container is to provide a
callback function to operate on each item of the list. The Standard
Template Library does this with functions such as "transform" or
"for_each". (Yes, there is a for_each
http://www.cplusplus.com/reference/algorithm/)
You provide a "functor" which operates on each member of the list.
What happens if you want to stop the process early? Like you want to
use for_each to search for an particular item and finish the
iterations when you find it? What happens if there is an error during
this process. The STL ignores the return value of the functor so you
cannot signal an end that way. Solution? Throw an exception. The
entire iteration will be aborted and you can catch this exception and
resume your work from there.

Disease: Error handling code doesn't get tested.

Your program is testing and goes into production but you still get
crashes. What the heck? One reason this happens is that error handling
code, code that executes only when errors happen doesn't get tested as
well as the main code. Why not? Because to test an error, you have to
make that error happen and black box testers can't always make this
happen. If you are using exceptions to handle errors you can do this:

Error handling code is hard to test because it only gets executed
during errors which are often rare, however, there is a way, if you
are using try/catch to easily test your error handling code. Say you
have some code like this:

try
{
socket.Connect("127.0.0.1:80");
}
catch(const std::exception& ex)
{
delete socket;
Log("Could not connect to %s");
}

There is a bug in the error handling code (no argument for the %s).

What you can do is go through your code and replace catch() with a
macro CATCH()

try
{
socket.Connect("127.0.0.1:80");
}
CATCH(const Exception& ex)
{
delete socket;
Log("Could not connect to %s");
}

Now, define CATCH(X) catch(X) {};

So now your code expands to this:

try
{
socket.Connect("127.0.0.1:80");
}
catch (const Exception& ex)
{
}

{
delete socket;
Log("Could not connect to %s");
}

Which makes the error handling code ALWAYS EXECUTE. Now you run your
code. The catch block you wrote to handle the error ALWAYS gets called
and tested. When you've tested it, you remove the CATCH macro on that
single piece of code and run the program again exercising the NEXT
catch block. Keep doing this until all your error handling code (catch
blocks) is tested.

Disease: Programmers killing a thread instead of exiting it cleanly.

Even though I said exceptions should only be used to handle error
conditions, I'm going to backtrack now. One of the neat things about
computer programming is that the inventors of something are often not
the best users of that that thing! Sometimes you can find novel uses
for something never intended to be used that way.

If you have ever programmed using multi-threading you have come across
the problem of "how do I properly stop a thread that is running?". You
cannot just stop the thread by killing it, you must somehow make the
thread return to its starting point so that all intervening resources
it was using are cleaned up. If you just kill the thread using the
operating system facilities you can leave memory leaks, open files,
unreleased mutexes and all sorts of nasty messes.

The solution to this is to somehow make your thread throw a special
exception, not derived from std::exception because you don't want it
caught by any normal error code. You only catch it in your thread's
opening function before you did anything significant that might need
cleanup. I will write another article on this at another time.

Here is a rich but simple exception class that I recommend you start
using as soon as possible.

#include <exception>
#include <string>
#include <cerrno>

// This STRINGIZE mumbo jumbo is necessary to turn __LINE__ into a
string using only macro syntax
#define STRINGIZE(S) REALLY_STRINGIZE(S)
#define REALLY_STRINGIZE(S) #S

// The ErrorLocation() macro will turn into the file and line where it
is used, like myfile:234
#define ErrorLocation() (__FILE__ ":" STRINGIZE(__LINE__))

class Exception: public std::exception
{
int SystemError;
int ApplicationError;
std::string Location;
std::string Message;
mutable std::string What; // Necessary kludge to deal
with std::exception being lame and returning const char* for what()

public:
Exception(const std::string& message, const std::string&
location = "", int systemError = 0, int applicationError = 0)
: Message(message), Location(location),
SystemError(systemError), ApplicationError(applicationError)
{
// If the caller doesn't set the error,
derive it from the last error the system is aware of
if (systemError == 0)
systemError = errno;
}

const char* what()
{
char errorString[1024] = "Unknown";

// If strerror fails, errorString will
remain set to "Unknown"
strncpy(errorString,
strerror(SystemError), sizeof(errorString));

What = "What: " + Message + "\n" +
// Only display system error system if
there was one (non-zero)
(SystemError > 0 ? std::string("Why: ") +
errorString + "\n" : "") +
// Only display location if we had set it
in the constructor
(Location.empty() ? "" :
std::string("Where: ") + Location + "\n");

return What.c_str();
}

~Exception() throw()
{
}
};


For simplicity's sake I did not add certain things like access
functions to get the Location and Message if those are the only ones
you might want to display. You can add those easily enough if they
become necessary.

The what() function is there so if you catch(const std::exception& ex)
calling ex.what() will show the more complete error information in
class Exception.

Then you can actually throw an exception like this:

FILE* file = fopen("20th_Century_French_Battle_Victories.txt");
If (!file)
throw
Exception("20th_Century_French_Battle_Victories.txt",
ErrorLocation());

Now, when you catch that exception, and use the what() function, the
error string will be something very complete like:

What: 20th_Centry_French_Battle_Victories.txt
Why: File does not exist
Where: FindFiles.cpp:244

This saves you minutes looking up error codes etc. and helps not break
your concentration while debugging, all in a few lines of code.

Now that you have a good exception class, how do you use it?

The most important thing about using exceptions is to be very clear
about what an exception is. If you want your code to make the jump to
light speed you can't go halfway with exceptions. A lot of programmers
are stuck between the old and new paradigms. I hear this quite often
and it's a problem, "Exceptions are for fatal errors but I still use
return codes for some things". This is not going to work nearly as
well. A very simple and clear criteria for using exceptions is, throw
an exception when a function fails to perform its function. This
means, no more error code returns at all, none, nada, zilch.

When I bring this up with some programmers I use the fopen() argument.
If you have a function that opens a file, should it return a valid
file handle if it succeeds, and NULL if it fails? If you said return
NULL you aren't getting what I'm saying. If your program is depending
on the file to open and it fails, that's the exact situation that
requires an exception.

A failure to perform its task IS fatal for that function. You cannot
know ahead of time how serious a failure of your function will be to
the program using it. Exceptions were invented to fix problems with
error handling. If you don't use them you are stuck with the same old
problems.

You need to use this definition of Exception, "An exception occurs
when a function cannot accomplish its expected task".

C++ Deficiencies

Compared to some languages, C++ provides only very basic exception
capabilities, however the capabilities it does provide allow you to
build almost all the advanced capabilities other languages include by
default in their exceptions. One thing that is difficult to add for C+
+ exceptions is a stack trace. This is because there is no standard
for stack traces in the language. You must add your own and this is
problematic because different co mpilers and different processors
treat the stack very differently.

In later articles I will show you how to add stack traces to your
exceptions but that is beyond the scope of this article.

Bad ways to use exceptions

I've seen a lot of strange code in my day from programmers who weren't
really sure how to use exceptions. Once you understand that exception
throwing is simply a way to return up the stack an arbitrary distance,
everything else falls into place. Here are some examples of how NOT to
use exceptions:

Bad Use: Never throw and catch an exception in the same function.

Exceptions exist as a new and revolutionary way to signal function
failures. But some programmers are using them to create a "cleanup"
routine at the end of a function. Throwing and catching in the same
function is a sure sign of improper exception use. It means you
haven't gotten the idea that a failed function, fails by throwing an
exception that is caught by someone else.

FILE* afunction(void) //VERY WRONG and just plain redundant
{
File* file = fopen("afile.txt", "r");
try
{
if (!file)
throw Exception("Could not
open file");
}
catch(Exception& e)
{
return NULL;
}
return file;
};

This is really silly. And all permutations of this type of thing are
silly also. Because they are simply returning an error code anyway or
catching the exception and dealing with it, meaning, the function did
not fail, it was able to handle the situation. Never throw and catch
an exception in the same function! Exceptions should be used to signal
a failed function. If you use exceptions for trivial conditions that
aren't function failures you will end up increasing the clutter in
your code. If your function fails, throw an exception, don't catch it
and translate back into the bad old return code habit. The above
function should be written like this if you insist on using return
codes:

FILE* afunction(void) // Bad, old fashion but at least not a corrupted
use of exceptions
{
File* file = fopen("afile.txt", "r");9
return file;
};

Bad Use: Don't "half-use" exceptions

Many programmers, and even the standard library, have the idea that
exceptions should be reserved for "fatal" errors only. They still use
old style return codes in many functions. There is a huge flaw in the
logic of this approach. A failure to perform its function is fatal to
the function involved. Only the catcher of an exception can know if
the exception is fatal to the program or not. You cannot possibly
predict 100% how your class will be used. If your class has any
success at all it will be reused in ways you never imagined. If you
use an exception class based on std::exception you will not limit
future users of your class.

For short utility programs, dying if an exception is thrown no big
deal, but the bigger or longer running a program is, the more likely
errors must be recoverable. If you are writing pacemaker software,
every error must be recoverable. However, the fatality of the
exception isn't decided by the thrower, it's decided by the catcher of
the exception. If you are programming a library of code that is
intended to be re-used (and why aren't yo u?) it isn't up to you to
decide how an error in your library will affect the program using it?
Use exceptions and let the user decide.

Bad Use: catch(�)

Normally you never want to use catch(...). This catches ALL exceptions
but you cannot know what type of exception was caught or any
information about that exception. Often programmers say to themselves
"oh well, if anything happens here I don't care, just ignore it". This
is not in itself a problem but as code grows, that original code being
try/catch protected might grow and often you will need to know what's
going on and cannot simply suppress errors. There is also this factor:
when you ship a product it's better that it continue to run and
recover wherever possible. Users are very critical of obvious crashes
and might not even notice subtle errors so

One solution is to catch(�) in shipping code so your users see fewer
of your warts and perhaps the program can limp along still functional,
however, during development you never want to suppress errors. Using a
macro for catch(�) will do the trick:

#ifdef _DEBUG
#define CATCHALL catch(const Exception& e)
#else
#define CATCHALL catch(�)
#endif

Bad Use: Not having exception safe functions

When you program using exceptions there is one slight change you have
to make in your style. Your code must be written so that it can handle
an exception being thrown any time your function calls any other
function that might throw an exception. When an exception gets thrown
your function will be exited immediately at that point. Any local
variables will be destructed just as in a normal return. Remember, an
exception occurring is basically just a return occurring as far as
your programming approach. This is actually very easily done by simply
declaring certain variables using auto_ptr which is part of the C++
standard library. I will write an article dedicated to this in the
future but you can research that yourself if you demand immediate
satisfaction.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Nevin :-] Liber

unread,
Mar 7, 2010, 3:31:35 AM3/7/10
to
In article
<ebd4c02a-99cc-41c1...@o3g2000yqb.googlegroups.com>,
"Walter...@gmail.com" <walter...@gmail.com> wrote:

> Bad Use: Don't "half-use" exceptions
>
> Many programmers, and even the standard library, have the idea that
> exceptions should be reserved for "fatal" errors only. They still use
> old style return codes in many functions. There is a huge flaw in the
> logic of this approach.

I'm one of those many programmers, and I see a huge flaw in only using
exceptions (as well as a huge flaw in only using return codes, such as
espoused at <http://www.joelonsoftware.com/items/2003/10/13.html>).

The analogy I like to give is that using return codes is like driving on
surface streets, while using exceptions is like taking the expressway.
Each has an appropriate use.

> A failure to perform its function is fatal to
> the function involved.

You are assuming a function even knows that it failed. Functions
usually have no idea why they are being called.

Take std::find. Is it really "failure" if it returns its second
parameter? Doesn't it really depend on whether or not the caller
expects the element to be in the range being searched? What if the
caller looked like:

// Bug if element is still in c
assert(std::find(c.begin(), c.end(), element) == c.end());

If std::find, instead of returning c.end() to indicate the element isn't
in the range, threw find_exception, the code would be a bit messier, as
in:

#ifndef NDEBUG
// Bug if element is still in c
try { std::find(c.begin(), c.end(), element); assert(false); }
catch (find_exception&) {}
#endif

The inversion of having failure detection inside a try block and having
success be the empty catch block makes this code much harder to
understand, yet there really is no way around it if you are using
exceptions instead of return codes, because the callee, not the caller,
has to decide what is "success" and what is "failure".

Things that are expected to be handled directly by the caller are
usually sent in return codes; things that are expected to be handled at
a much higher level are usually sent via exceptions (at least in the
code that I have influence over).

--
Nevin ":-)" Liber <mailto:ne...@eviloverlord.com> 773 961-1620

A. McKenney

unread,
Mar 7, 2010, 9:50:24 AM3/7/10
to
I'm one of those programmers who rarely if ever uses exceptions.

The biggest reason is that exceptions are expensive. I've spent
a lot of time replacing exceptions with error returns (or
error work-arounds), because we could not afford the time spent
handling them. My applications handle real-time data, and if
your program is slow, you drop data. It is a bad trade-off to
handle a little bit of bad data elegantly while dropping lots
of good data to do so.

While most of the errors we deal with have to be dealt with quickly
so the program can move on, there _are_ cases where this is not
appropriate. However, in those cases, it ends up making
more sense to log an error and abort the whole process, rather
than throwing an exception.

There are cases where I've used exceptions, but these were
in cases where performance didn't matter at all, or where
the situation it was handling would already cost so much
time that even if exception handling cost a second or two,
it wouldn't matter.

--

Thomas Richter

unread,
Mar 7, 2010, 5:00:46 PM3/7/10
to
A. McKenney wrote:
> I'm one of those programmers who rarely if ever uses exceptions.
>
> The biggest reason is that exceptions are expensive. I've spent
> a lot of time replacing exceptions with error returns (or
> error work-arounds), because we could not afford the time spent
> handling them.

Could you provide evidence for that? The reason why I'm asking is that
unwinding manually by passing through return codes is *also* expensive,
basically because more or less the same activities take place that would
take place in exception processing - just in a messier way. That is,
local objects are destroyed, the stack is unwound - just in the regular
way. Rather the reverse, the "normal" program execution path takes
longer because you now *also* have to check return codes.

> There are cases where I've used exceptions, but these were
> in cases where performance didn't matter at all, or where
> the situation it was handling would already cost so much
> time that even if exception handling cost a second or two,
> it wouldn't matter.

If unwinding an exception takes *seconds*, then either you or your
compiler does something pretty wrong. (-;

So long,
Thomas

Mathias Gaunard

unread,
Mar 7, 2010, 8:29:43 PM3/7/10
to
On 7 mar, 14:50, "A. McKenney" <alan_mckenn...@yahoo.com> wrote:
> I'm one of those programmers who rarely if ever uses exceptions.
>
> The biggest reason is that exceptions are expensive. I've spent
> a lot of time replacing exceptions with error returns (or
> error work-arounds), because we could not afford the time spent
> handling them. My applications handle real-time data, and if
> your program is slow, you drop data. It is a bad trade-off to
> handle a little bit of bad data elegantly while dropping lots
> of good data to do so.

If errors happen often enough that it has such effects, then obviously
it is part of the program logic to deal with it and whether there is
an error or not should be part of the state of the subsystem in
question.
Exceptions are for exceptional situations (things that shouldn't
happen in a "normal" run of your program), that are handled separately
from normal control flow.

Joshua Maurice

unread,
Mar 8, 2010, 4:01:04 AM3/8/10
to
On Mar 7, 2:00 pm, Thomas Richter <t...@math.tu-berlin.de> wrote:
> A. McKenney wrote:
> > I'm one of those programmers who rarely if ever uses exceptions.
>
> > The biggest reason is that exceptions are expensive. I've spent
> > a lot of time replacing exceptions with error returns (or
> > error work-arounds), because we could not afford the time spent
> > handling them.
>
> Could you provide evidence for that? The reason why I'm asking is that
> unwinding manually by passing through return codes is *also* expensive,
> basically because more or less the same activities take place that would
> take place in exception processing - just in a messier way. That is,
> local objects are destroyed, the stack is unwound - just in the regular
> way. Rather the reverse, the "normal" program execution path takes
> longer because you now *also* have to check return codes.
>
> > There are cases where I've used exceptions, but these were
> > in cases where performance didn't matter at all, or where
> > the situation it was handling would already cost so much
> > time that even if exception handling cost a second or two,
> > it wouldn't matter.
>
> If unwinding an exception takes *seconds*, then either you or your
> compiler does something pretty wrong. (-;

It's generally accepted that throwing and catching exceptions in C++
on common desktops and servers is several magnitudes slower than
unwinding the stack with returns. There is no particular Big O reason
for this to be the case, but most computers are not random-access
equivalent machines, so the simplistic Big O analysis does not hold.
In particular, exceptions on such systems tend to be optimized for the
case that they are not thrown. In a good C++ implementation for a
machine with caching, the "catch" code is out-of-band, not in the
function body, and instead located far far off elsewhere. This allows
quicker execution for the "not thrown" case due to higher cache hit
rates. However, with this implementation, when an exception is thrown,
you're looking at the entire instruction pipeline being thrown out and
probably a virtual page fault, and that is many many times slower than
a simple branch.

Daniel T.

unread,
Mar 8, 2010, 2:16:55 PM3/8/10
to
Mathias Gaunard <louf...@gmail.com> wrote:
>
> If errors happen often enough that it has such effects, then obviously
> it is part of the program logic to deal with it and whether there is
> an error or not should be part of the state of the subsystem in
> question.

There is something funny in the above sentence... Something about the
idea that errors shouldn't happen often enough to have bad effects...
Maybe it's just me... :-D

Seungbeom Kim

unread,
Mar 8, 2010, 2:14:19 PM3/8/10
to
Walter...@gmail.com wrote:
>
> Disease: Return codes corrupt the meaning of the word "function" and
> destroy the code's usability as a function
>
> Mathematically speaking, the definition of a function is this: http
> http://en.wikipedia.org/wiki/Function_%28mathematics%29. It's
> important to note that a function translates multiple inputs into
> exactly one output.

It doesn't mean very much to say "exactly one output", since that
"exactly one output" can also be one object containing an arbitrary
number of subobjects. For example, std::set<T>::insert(T) returns a
std::pair<std::set<T>::iterator, bool>.

> Disease: Functions tangled with return code checking, propagate their
> problems to anyone else using them, spreading complexity like a
> cancer.
>

> [...] The iostream library, bless


> its heart, was written before exceptions were part of the language. I
> suggest if you use it, wrapping it in your own classes that do throw
> exceptions if failures occur.

No need to write your own classes; just call
std::basic_ios<...>::exceptions(std::ios_base::iostate).

> Disease: Error handling code doesn't get tested.
>

[...]


>
> What you can do is go through your code and replace catch() with a
> macro CATCH()
>
> try
> {
> socket.Connect("127.0.0.1:80");
> }
> CATCH(const Exception& ex)
> {
> delete socket;
> Log("Could not connect to %s");
> }
>
> Now, define CATCH(X) catch(X) {};
>
> So now your code expands to this:
>
> try
> {
> socket.Connect("127.0.0.1:80");
> }
> catch (const Exception& ex)
> {
> }
>
> {
> delete socket;
> Log("Could not connect to %s");
> }
>
> Which makes the error handling code ALWAYS EXECUTE. Now you run your
> code. The catch block you wrote to handle the error ALWAYS gets called
> and tested. When you've tested it, you remove the CATCH macro on that
> single piece of code and run the program again exercising the NEXT
> catch block. Keep doing this until all your error handling code (catch
> blocks) is tested.

This works only for the last handler in any given handler sequence;
i.e. it breaks when there is another subsequent handler.

Why don't you just insert a throw expression in the try block?
It doesn't have such a limitation (or bug), is simpler, and can even
be configured run-time without recompiling; for example:

try {
// ...
if (TestingSomeException)
throw SomeException(...);
// ...
}
catch (const SomeException& e) {
// ...
}
catch (const AnotherException& e) {
// ...
}

(Don't use preprocessor for what other techniques can work better.)

By the way, it's strange that you're not using a smart pointer and RAII
in the example, while advocating the exceptions so much. :)

>
> Here is a rich but simple exception class that I recommend you start
> using as soon as possible.
>

[...]


>
> class Exception: public std::exception
> {
> int SystemError;
> int ApplicationError;
> std::string Location;
> std::string Message;
> mutable std::string What; // Necessary kludge to deal
> with std::exception being lame and returning const char* for what()

You probably mean it's because what() is a const member function,
not because what() returns const char*. (In fact, with the definition
of what() you give below, What doesn't have to be mutable.)

>
> public:
> Exception(const std::string& message, const std::string&
> location = "", int systemError = 0, int applicationError = 0)
> : Message(message), Location(location),
> SystemError(systemError), ApplicationError(applicationError)
> {
> // If the caller doesn't set the error,
> derive it from the last error the system is aware of
> if (systemError == 0)
> systemError = errno;
> }

You access errno only after constructing several members, but its value
could have been changed by library function calls in the middle.
It should be checked (including being saved to another variable) right
after the call reporting the error but before any other subsequent calls.

>
> const char* what()
> {
> char errorString[1024] = "Unknown";
>
> // If strerror fails, errorString will
> remain set to "Unknown"
> strncpy(errorString,
> strerror(SystemError), sizeof(errorString));

The definition of strerror in the standard (ISO/IEC 9899:1999 7.21.6.2)
seems to imply that it can never "fail":

p2: [...] strerror shall map any value of type int to a message.
p4: The strerror function returns a pointer to the string [...].

>
> What = "What: " + Message + "\n" +
> // Only display system error system if
> there was one (non-zero)
> (SystemError > 0 ? std::string("Why: ") +
> errorString + "\n" : "") +
> // Only display location if we had set it
> in the constructor
> (Location.empty() ? "" :
> std::string("Where: ") + Location + "\n");
>
> return What.c_str();
> }

Wow, how many operator+'s and how many temporaries do we get here? :)

It's weird that you keep What as a member but compute its value in
every call to what(); you could have cached it in the first call and
skipped the computation in later calls if you wanted a lazy evaluation,
or computed it once early in the constructor (and even make What non-
mutable).

I do not know the general consensus on the usage of what(), but many
people hold that it doesn't have to be the final string to be logged or
shown to the user but a simple key or index to a message in a catalog.
My feeling is that otherwise the exception class itself could need to
do too much work (such as formatting and localization) or could be too
inflexible.
I'm also worried that this function or this class may be too heavy.

> Now that you have a good exception class, how do you use it?
>
> The most important thing about using exceptions is to be very clear
> about what an exception is. If you want your code to make the jump to
> light speed you can't go halfway with exceptions. A lot of programmers
> are stuck between the old and new paradigms. I hear this quite often
> and it's a problem, "Exceptions are for fatal errors but I still use
> return codes for some things". This is not going to work nearly as
> well. A very simple and clear criteria for using exceptions is, throw
> an exception when a function fails to perform its function. This
> means, no more error code returns at all, none, nada, zilch.

That may be a nice world to live in, but we're in a world that already
carries the burden of backward compatibility; we cannot get away with
well-established and widely-used APIs that follow the "old" paradigm.

Following the "new" paradigm may be possible when all those "old" stuff
are wrapped nicely in a modern C++ fashion, but I find myself still
directly using the Berkeley socket interface even in C++...

> Bad Use: catch(�)
>
[...]


>
> One solution is to catch(�) in shipping code so your users see fewer
> of your warts and perhaps the program can limp along still functional,
> however, during development you never want to suppress errors. Using a
> macro for catch(�) will do the trick:
>
> #ifdef _DEBUG
> #define CATCHALL catch(const Exception& e)
> #else
> #define CATCHALL catch(�)
> #endif

Then what do you do in the catch block? I cannot think of anything
significantly more than an empty block or a mere writing of "something
bad happened". You cannot use the caught exception e even in the debug
build; discarding the information by using such a 'unified' catch block
doesn't look like a good idea.

--
Seungbeom Kim

Daniel T.

unread,
Mar 8, 2010, 2:16:34 PM3/8/10
to
"Walter...@gmail.com" <walter...@gmail.com> wrote:

Your not quite there IMHO, but you are close. I suggest you read up on
design by contract. Exceptions should be used when contracts are broken.

Whenever you write a function you have to ask yourself:

What does the function require?
What does the function guarantee?

Now, obviously if you are writing a function and it fails to meet its
guarantees despite having everything it requires, you have written the
function incorrectly. In this case, you couldn't have thrown an
exception before knowing the error existed, and once you discover the
error, you should fix the code rather than add code to throw an
exception.

However, when you are writing a function, what should that function do
if its requirements have not been met? This is where exceptions come in.
The function cannot do its job (whatever that is,) because it doesn't
have what it needs to get the job done.

Good examples of proper exception use are already in the standard
library, so let's have a look at some:

Both vector and deque have member-functions called "at()" and these
functions are guaranteed to return the value at a particular index
within the container. In order for the function to be able to meet its
guarantee, it requires that the parameter passed in refers to an element
in the container. Giving a bad parameter is a requirement violation, the
function cannot do its job, so it throws an exception.

When dynamic_cast is passed a reference, it guarantees that it will
return the the referenced object as the specified derived type. The
function requires that the referenced object actually is the type
specified. If its requirements aren't met, then it can't do its job, so
it throws an exception.

The above are just two examples, but you get the idea I'm sure.

For your example, the fact that your FileOpen function throws an
exception if the file doesn't exist means that it is an *error* to call
FileOpen and pass in the name of a nonexistent file. What this means is
that if FileOpen throws its exception during some run of the program,
you should *not* add a catch, instead you should fix the code so the
exception is no longer thrown.

If your code is littered with catches that are empty, or catches that do
something other than error logging and re-throw/exit, then you have
poorly written code.

It is important for functions to throw exceptions when they can't do
their specified jobs, but catches should be nearly absent from the code
base.

Seungbeom Kim

unread,
Mar 8, 2010, 5:05:23 PM3/8/10
to
Daniel T. wrote:
>
> However, when you are writing a function, what should that function do
> if its requirements have not been met? This is where exceptions come in.
> The function cannot do its job (whatever that is,) because it doesn't
> have what it needs to get the job done.
>
> Good examples of proper exception use are already in the standard
> library, so let's have a look at some:
>
> Both vector and deque have member-functions called "at()" and these
> functions are guaranteed to return the value at a particular index
> within the container. In order for the function to be able to meet its
> guarantee, it requires that the parameter passed in refers to an element
> in the container. Giving a bad parameter is a requirement violation, the
> function cannot do its job, so it throws an exception.

I think you could also say that, in some cases and particularly in
the cases of the element access for vector and deque, passing a bad
parameter is a bug in the program and thus should be dealt with with
assertions. My feeling is that at() is for not-the-most-common cases
where the element indices come from outside the program, e.g. when
working with sparse matrix formats in which indices are part of the data.

> For your example, the fact that your FileOpen function throws an
> exception if the file doesn't exist means that it is an *error* to call
> FileOpen and pass in the name of a nonexistent file. What this means is
> that if FileOpen throws its exception during some run of the program,
> you should *not* add a catch, instead you should fix the code so the
> exception is no longer thrown.

How do you fix the program so that opening a nonexistent file doesn't
occur? How do you know that the file is nonexistent and cannot be opened
until you really try to open it?

--
Seungbeom Kim

Nevin :-] Liber

unread,
Mar 8, 2010, 5:04:03 PM3/8/10
to
In article
<daniel_t-826A9D...@70-3-168-216.pools.spcsdns.net>,
"Daniel T." <dani...@earthlink.net> wrote:

> Your not quite there IMHO, but you are close. I suggest you read up on
> design by contract. Exceptions should be used when contracts are broken.

If it is a contract violation due to a programming error, it should be
an assertion, not an exception. Exceptions can be part of the contract.

> Both vector and deque have member-functions called "at()" and these
> functions are guaranteed to return the value at a particular index
> within the container. In order for the function to be able to meet its
> guarantee, it requires that the parameter passed in refers to an element
> in the container. Giving a bad parameter is a requirement violation, the
> function cannot do its job, so it throws an exception.

The way I see it, an out of range index passed to operator[] is a
contract violation, while an out of range index passed to at() is
perfectly acceptable.

--
Nevin ":-)" Liber <mailto:ne...@eviloverlord.com> 773 961-1620

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Nevin :-] Liber

unread,
Mar 8, 2010, 5:01:37 PM3/8/10
to
In article
<e10fe54e-1e99-4658...@t17g2000prg.googlegroups.com>,
Joshua Maurice <joshua...@gmail.com> wrote:

> It's generally accepted that throwing and catching exceptions in C++
> on common desktops and servers is several magnitudes slower than
> unwinding the stack with returns.

But I could say the same thing about heap allocations vs. stack
allocations. Yet those preaching "avoid exceptions" still, for the most
part, use the heap with reckless abandon.

> In particular, exceptions on such systems tend to be optimized for the
> case that they are not thrown.

So, in order to compare using exceptions with using return codes, one
has to do a probabilistic analysis on how often the exception would be
thrown in practice to infer which program would overall run faster.
That, or write the program both ways and measure it.

The tradeoff isn't just speed; it's about correctness and the ability to
reason about the code. Using exceptions to avoid things like two phase
construction are a definite win from a usability point of view.

I'm not saying that there is never a time to avoid exceptions. But for
the most part, if people aren't backing that avoidance with solid
numbers or a complexity analysis, it is just another premature
optimization.

--
Nevin ":-)" Liber <mailto:ne...@eviloverlord.com> 773 961-1620

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Daniel T.

unread,
Mar 9, 2010, 12:22:20 AM3/9/10
to
"Nevin :-] Liber" <ne...@eviloverlord.com> wrote:
> "Daniel T." <dani...@earthlink.net> wrote:
>
> > Your not quite there IMHO, but you are close. I suggest you read up
> > on design by contract. Exceptions should be used when contracts are
> > broken.
>
> If it is a contract violation due to a programming error, it should be
> an assertion, not an exception. Exceptions can be part of the
> contract.

All contract violations are due to programming error. The contract
defines normal (correct) program control flow. Exception handling is not
for normal control flow, it is for error handling.

"If an exception is expected and caught so that it has no bad effects on
the behavior of the program, then how can it be an error?" -- Stroustrup

The problem with assertions is that in some domains, aborting the
program is unacceptable. Exceptions provide a means of cleaning up,
maybe saving some state and restarting or whatever. When library code
finds an error, it cannot take it upon itself to abort the program
without giving the calling code an opportunity to clean up. The function
author should not make assumptions about how the calling code wants to
handle an error.

Interestingly, I was reviewing some old posts of mine and saw that I
held your position (contract violations should be met with assertions,)
back around 2001 or so. I guess I changed my mind in the intervening
nine years.

> > Both vector and deque have member-functions called "at()" and these
> > functions are guaranteed to return the value at a particular index
> > within the container. In order for the function to be able to meet
> > its guarantee, it requires that the parameter passed in refers to an
> > element in the container. Giving a bad parameter is a requirement
> > violation, the function cannot do its job, so it throws an exception.
>
> The way I see it, an out of range index passed to operator[] is a
> contract violation, while an out of range index passed to at() is
> perfectly acceptable.

class Foo {
std::vector<int> vec;
public:
// other functions

int getValA(int idx) const {
if (0 <= idx && idx < vec.size())
return vec[idx];
return 0;
}

int getValB(int idx) const {
try {
return vec.at(idx);
}
catch (std::out_of_range) {
return 0;
}
}
};

(I used two returns instead of a result variable just for you. :-)

Both getValA and getValB have the same contract, but you seem to be
asserting that getValB is "perfectly acceptable." Do I understand you
correctly?

... such use of exceptions can easily be overused and lead to
obscure code. Whenever reasonable, one should stick to the
"exception handling is error handling" view. When this is done, code
is clearly separated into two categories: ordinary code and
error-handling code. This makes code more comprehensible.
-- Stroustrup

Stroustrup does remind us that the real world is a messy place and
sometime code gets messy too, but the primary point remains. Be
reasonable... use exceptions to flag errors, and fix errors when they
are found.

Please consider reading (or re-reading) "The C++ Programming language"
section 14.5.

--

Daniel T.

unread,
Mar 9, 2010, 12:23:11 AM3/9/10
to
Seungbeom Kim <musi...@bawi.org> wrote:

> Daniel T. wrote:
>
> > For your example, the fact that your FileOpen function throws an
> > exception if the file doesn't exist means that it is an *error* to call
> > FileOpen and pass in the name of a nonexistent file. What this means is
> > that if FileOpen throws its exception during some run of the program,
> > you should *not* add a catch, instead you should fix the code so the
> > exception is no longer thrown.
>
> How do you fix the program so that opening a nonexistent file doesn't
> occur? How do you know that the file is nonexistent and cannot be opened
> until you really try to open it?

I expect you thought about your question after posting, and you figured
out the answer... If not...

Let's say your program needs to display some bmp image for a button (I
do this all the time in games and educational software.) Let's also say
that the file is nonexistent. How do you fix that? The obvious answer is
to make the bmp file and put it where it belongs.

Let's say that there is some file that *must* exist at location Y in
order for your program to work properly. What should the code that
attempts to open the non-existant file do?
a) Should it simply abort the entire program with no information given
to the user as to why and without attempting to save any user generated
content?
b) Should the function crash the program because assertions were
compiled out of the release version?
c) Should the function throw an exception so that the program can exit
cleanly with a message telling the user to re-instal or whatever?

To me, answer (c) is correct, but maybe you can think of a better answer?

--

Joshua Maurice

unread,
Mar 9, 2010, 12:20:31 AM3/9/10
to
On Mar 8, 2:01 pm, "Nevin :-] Liber" <ne...@eviloverlord.com> wrote:
> In article
> <e10fe54e-1e99-4658-bce5-152de76d9...@t17g2000prg.googlegroups.com>,

> Joshua Maurice <joshuamaur...@gmail.com> wrote:
>
> > It's generally accepted that throwing and catching exceptions in C++
> > on common desktops and servers is several magnitudes slower than
> > unwinding the stack with returns.
>
> But I could say the same thing about heap allocations vs. stack
> allocations. Yet those preaching "avoid exceptions" still, for the most
> part, use the heap with reckless abandon.
>
> > In particular, exceptions on such systems tend to be optimized for the
> > case that they are not thrown.
>
> So, in order to compare using exceptions with using return codes, one
> has to do a probabilistic analysis on how often the exception would be
> thrown in practice to infer which program would overall run faster.
> That, or write the program both ways and measure it.
>
> The tradeoff isn't just speed; it's about correctness and the ability to
> reason about the code. Using exceptions to avoid things like two phase
> construction are a definite win from a usability point of view.
>
> I'm not saying that there is never a time to avoid exceptions. But for
> the most part, if people aren't backing that avoidance with solid
> numbers or a complexity analysis, it is just another premature
> optimization.

Note that I did not support exception use or say avoid all exception
use anywhere in my post. Please do not attribute arguments to me which
I did not make. I was merely stating facts about the performance of
exceptions on current desktops and servers to correct misinformation
from Thomas Richter. He suggested that return codes and exception have
roughly the same work to do and should be about as fast. (As I
explained thoroughly, this is not true for common desktops and
servers, though perhaps it is true for machines which have actual
equal random access performance characteristics, perhaps something
embedded.)

As a matter of opinion, I very much like exceptions, and I still use
them in products I consider relatively performance critical (such as
my home-brewed GNU Make replacement) because it's so much easier to
write C++ code using them, and when properly done the performance hit
is rather small.


--

Mathias Gaunard

unread,
Mar 9, 2010, 8:18:48 AM3/9/10
to
On 8 mar, 19:16, "Daniel T." <danie...@earthlink.net> wrote:

> Mathias Gaunard <loufo...@gmail.com> wrote:
>
> > If errors happen often enough that it has such effects, then obviously
> > it is part of the program logic to deal with it and whether there is
> > an error or not should be part of the state of the subsystem in
> > question.
>
> There is something funny in the above sentence... Something about the
> idea that errors shouldn't happen often enough to have bad effects...

It's merely a matter of determining what the typical normal run of a
program is, and what the responsabilities of the subsystem is.
Well typically, if you have a non-trivial subsystem modeled, you're
going to want to handle errors internally anyway. Errors that are not
the responsability of the subsystem should throw.

Seungbeom Kim

unread,
Mar 9, 2010, 9:47:49 PM3/9/10
to
Daniel T. wrote:
> Seungbeom Kim <musi...@bawi.org> wrote:
>> Daniel T. wrote:
>>
>>> For your example, the fact that your FileOpen function throws an
>>> exception if the file doesn't exist means that it is an *error* to call
>>> FileOpen and pass in the name of a nonexistent file. What this means is
>>> that if FileOpen throws its exception during some run of the program,
>>> you should *not* add a catch, instead you should fix the code so the
>>> exception is no longer thrown.
>> How do you fix the program so that opening a nonexistent file doesn't
>> occur? How do you know that the file is nonexistent and cannot be opened
>> until you really try to open it?
>
> I expect you thought about your question after posting, and you figured
> out the answer... If not...

You are implying it was so silly a question that I could figure out
the answer myself later, but I was asking because I couldn't and
something was not clear about your argument.

>
> Let's say your program needs to display some bmp image for a button (I
> do this all the time in games and educational software.) Let's also say
> that the file is nonexistent. How do you fix that? The obvious answer is
> to make the bmp file and put it where it belongs.

What we're discussing here is what the program should do once it ships,
runs on the customer's computer and finds that it cannot open the file.
Of course it would be silly not to make and provide the file needed,
but you cannot guarantee that it will always stay intact: the user could
delete the file by mistake, or the file could have been installed in a
remotely mounted directory and the directory could be unmounted when
the program ran.

Another scenario I was thinking of is that the filename is supplied by
the user. You can never guarantee the file can be opened successfully.

>
> Let's say that there is some file that *must* exist at location Y in
> order for your program to work properly. What should the code that
> attempts to open the non-existant file do?
> a) Should it simply abort the entire program with no information given
> to the user as to why and without attempting to save any user generated
> content?
> b) Should the function crash the program because assertions were
> compiled out of the release version?
> c) Should the function throw an exception so that the program can exit
> cleanly with a message telling the user to re-instal or whatever?
>
> To me, answer (c) is correct, but maybe you can think of a better answer?

Of course I choose (c). Did I say or imply otherwise?

Your argument was: (repeated here)


> For your example, the fact that your FileOpen function throws an
> exception if the file doesn't exist means that it is an *error* to call
> FileOpen and pass in the name of a nonexistent file. What this means is
> that if FileOpen throws its exception during some run of the program,
> you should *not* add a catch, instead you should fix the code so the
> exception is no longer thrown.

I am saying that no matter how well you write your program, some run-time
failures are inevitable, in which exceptions can be thrown, and that you
should be prepared to catch them. And that it can be impossible to fix
the code so that exceptions are no longer thrown, and that it may not
be an error in the code.

--
Seungbeom Kim

Vidar Hasfjord

unread,
Mar 10, 2010, 10:43:12 AM3/10/10
to
On Mar 7, 8:31 am, "Nevin :-] Liber" <ne...@eviloverlord.com> wrote:
> [...]

> Take std::find. Is it really "failure" if it returns its second
> parameter?

No, it is part of the contract.

But the problem is the find function's dual duties: (1) return whether
or not the item exists in the range, and (2) return an iterator
pointing at that element. Those returns are not the same type (the
first is logically boolean). So a special iterator value, the end of
the range, is used to represent "not found".

Many functions are designed like this for the simple reason that the
work needed to perform (1) and (2) is nearly the same, and splitting
it up in two functions would duplicate work.

As it happens, this can be avoided with stateful programming in C++,
but it has never become fashionable as far as I know:

Finder f (c.begin (), c.end (), element);
if (f.has_element ())
Iterator i = f.locate ();

Whether or not Finder::locate is designed to throw for non-existant
elements may depend on its run-time requirements. Efficiency may be
important and it does no checking, leaving its behaviour undefined in
that case. Or safety may be important and it checks and throws.
Alternatively, you can have two members, one checked and one unchecked
("locate" and and "unchecked_locate"). This interface design is
similar to std::vector::at and std::vector::operator [].

This stateful idiom is applicable to many other dual-return functions
as well. I have found good use for it in geometry libraries. E.g. for
intersection:

Intersection i (line1, line2);
if (i.exists ())
Point p = i.locate ();

The technique is especially useful in this example because the
constructor does only the work needed to determine if the intersection
exists and the remaining work to locate the intersection is only done
when needed. This can eliminate work if you are only interested in
whether or not the intersection exists:

BOOST_FOREACH (const Line& a, lines)
if (Intersection (a, b).exists ()) ++count;

If you know that the intersection exists then you can eliminate a
branch (a potentially slow construct in modern CPUs):

Intersection i (line1, perpendicular);
assert (i.exists ());
Point p = i.locate ();

The traditional intersection function cannot do this. It encapsulates
the branch:

Point p;
bool success = intersection (line1, perpendicular, &p); // 3rd arg
is out-param
assert (success);

> Doesn't it really depend on whether or not the caller
> expects the element to be in the range being searched? What if the
> caller looked like:
>
> // Bug if element is still in c
> assert(std::find(c.begin(), c.end(), element) == c.end());

assert (Finder f (c.begin (), c.end (), element).has_element () ==
false);

>
> If std::find, instead of returning c.end() to indicate the element isn't
> in the range, threw find_exception, the code would be a bit messier, as
> in:
>
> #ifndef NDEBUG
> // Bug if element is still in c
> try { std::find(c.begin(), c.end(), element); assert(false); }
> catch (find_exception&) {}
> #endif

Throwing an exception for "find" is clearly wrong design. One of the
dual duties of "find" is to return whether or not the element is in
the range. A false outcome of that predicate is generally expected and
not an exception (inside "find" itself, that is).

On the other hand, asking "find" to return an iterator to the element
when it doesn't exist can be viewed as impossible and warrant an
exception. But that dilemma stems from the dual duties of the
function, which can be solved by splitting it up as I've shown above.

> The inversion of having failure detection inside a try block and having
> success be the empty catch block makes this code much harder to
> understand, yet there really is no way around it if you are using
> exceptions instead of return codes, because the callee, not the caller,
> has to decide what is "success" and what is "failure".

True in your example, but not in general. I think you are generalising
using a faulty example; the dual duty "find" function which is clearly
designed not to throw exceptions. I've shown above that with a
different design (Finder) it may make sense to throw an exception if
you ask for an iterator to a non-existing element (similar to an out-
of-range index causing an exception in std::vector::at).

> Things that are expected to be handled directly by the caller are
> usually sent in return codes; things that are expected to be handled at
> a much higher level are usually sent via exceptions (at least in the
> code that I have influence over).

I need a more convincing argument for error return codes than that.

The only plausable argument I've seen is performance, and even that I
suspect is rarely applicable.

Regards,
Vidar Hasfjord

--

Anthony Delroy

unread,
Mar 10, 2010, 10:44:26 AM3/10/10
to
On Mar 7, 10:18 am, "WalterHow...@gmail.com" <walterhow...@gmail.com>
wrote:
> C++ Exceptions
> ...

I really think people worry too much about defining some absolute rule
for exception use, then the arguments start as the exceptions are
raised ;-P.

First, understand what behaviours you want your program to have: i.e.
when some specific things happen, should you assert/abort right there
and then, do a little cleanup/reporting then abort, or find a way to
continue running? The choice of what you ideally want to do is
independent of the choice of exceptions versus return codes. These
are your target "pros" in your decision process.

Secondly, consider the "cons" about having to implementation your
choice: how would return codes, exceptions or some other mechanism
affect code clarity, concision, robustness, maintainability,
flexibility, consistency, and run-time performance, in achieving your
ideal. ONE important but not necessarily dominant part of clarity and
maintainability is meeting the vague but real expectations of the C++
developers who will work on the code, so unless there's net benefit,
you don't want to use (or not use) a handling mechanism in a way
that's controversial, confusing or surprising. You do want something
to work in with your general approach to QA / testing / real-time and
post-mortem production issue reporting and handling.

Consider your second and third choice mechanisms until you've
identified the handling with the best "pros vs cons". By definition,
to be selected it should be the biggest net benefit to your project:
that's the important thing, not whether someone somewhere raises an
eyebrow at the concept.

Now, in weighing up the pros and cons, it's important to understand
the basic differences between the candidate issue/error/exception/
whatever handling mechanisms. This is where there's some actual value
in the discussion, in as much as it informs the analysis of pros and
cons advocated above. I'm NOT going to try to be exhaustive here -
just to scratch the surface - but what I'm driving at is quantitative
differences in performance (measured on your system(s), and to the
limited extent that they're stable/predicatable and significant over
the lifetime of your app) and qualitative differences like:

- exceptions DISASSOCIATE handling from the code that needs it vs.
- this should make the issue-free flow of execution easier to
understand/maintain
- some other approaches - error state and nops ala floating point
NAN - might avoid constant explicit checks/handling too, but are less
general

- return codes LOCALISE handling with the code that needs it
- this might make issue-handling easier to understand/maintain -
more explicit when considering any given test for an issue - but may
be more redundant and obfuscating

- exceptions are great when one catch block can easily and
appropriately handle issues thrown from a large number of disparate
places

...and so on. I'm not even interested in listing them properly as I
don't believe an understanding of this is generally lacking on clc++m
- it's the step from that understanding to formulating usage policy
that so often goes awry. For whomever it may make sense to, I'll make
the aside that programming should be like consequentialist ethics, not
deontological! There is no evil in programming - there's only what
works best.

Some programmers may just be better at remembering to use one or
another approach consistently, especially if that's the only practice
they're familiar with. Many assume everyone else is the same as
them. Such is life, but as a group trying to reach a consensus, or a
senior developer setting standards for wider use, individuals should
try to understand that this is a grey area and shouldn't be a dominant
driver in decision making.

Making good design decisions about exception usage requires a
balanced, rational appreciation of these trade offs IN THE CONTEXT OF
THE SPECIFIC APPLICATION(S) AND DEVELOPMENT TEAM.

Cheers,
Tony

Martin B.

unread,
Mar 10, 2010, 10:42:48 AM3/10/10
to
Walter...@gmail.com wrote:
> Subject: I keep running into long term c++ programmers who refuse to use exceptions
> <snipped body>

What I found more interesting about this post that the examples given
was it's subject: The statement that we(?) keep running into C++
programmers that refuse to use exceptions. I find this disconcerting.
Like with everything there are pros and cons and there is Good usage of
exceptions and Bad usage, and there are cases where you have to live
without them.

Yet somehow there are people (coming from C land?) that seem to think
that exceptions are something that should be avoided because they don't
want to wrap there had around the concept or because "exceptions are
slow"[*] or because "an uncaught exception will crash the program" or
because of any other misconception regarding this tool.

Sometime I get the feeling that in C++ the meaning of the word exception
somehow implies that exceptions should occur rarely *in the code* rather
than are something that's common in the code and is just something that
happens rarely *at runtime*.

Just throwing an exception whenever you feel like it is just as wrong as
my personal favourite "if(error) return;".

br,
Martin


[*] Interestingly, exceptions are also expensive on the .NET platform,
(see:
http://blogs.msdn.com/tess/archive/2005/11/30/are-you-aware-that-you-have-thrown-over-40-000-exceptions-in-the-last-3-hours.aspx

) and still I don't think that people over there are debating their
usefulness.

Daniel T.

unread,
Mar 10, 2010, 10:47:33 AM3/10/10
to
Seungbeom Kim <musi...@bawi.org> wrote:
> Daniel T. wrote:
>
> What we're discussing here is what the program should do once it
> ships, runs on the customer's computer and finds that it cannot open
> the file.

That can't happen in my domain (console games.) A missing file means
that we screwed up. Same goes with a failed memory request.

> Another scenario I was thinking of is that the filename is supplied by
> the user. You can never guarantee the file can be opened successfully.

See below.

> Your argument was: (repeated here)
>
> > For your example, the fact that your FileOpen function throws an
> > exception if the file doesn't exist means that it is an *error* to
> > call FileOpen and pass in the name of a nonexistent file. What this
> > means is that if FileOpen throws its exception during some run of
> > the program, you should *not* add a catch, instead you should fix
> > the code so the exception is no longer thrown.

It looks like I overstated my case with the last clause of the last
sentence. Sorry about that.

> I am saying that no matter how well you write your program, some
> run-time failures are inevitable, in which exceptions can be thrown,
> and that you should be prepared to catch them. And that it can be
> impossible to fix the code so that exceptions are no longer thrown,
> and that it may not be an error in the code.

When designing a program, one of the cases we have to consider is what
to do if something goes wrong and a shutdown/reset is required. Whatever
procedure is decided on goes in catch block(s). In other words, you put
in catch blocks because you realize you need to do something special
before shutdown/reset when something goes wrong, you do *not* put them
in simply because a particular function might throw or because that
function threw during QA testing. In the simplest case, you don't need
to do anything before shutdown/reset and in that case there wouldn't be
any catches in the program at all, no matter how many throws might exist.

So we have two different scenarios on the table:
A) The program tries to open a file that is necessary for correct
function. This file is provided with the program and put in the correct
place during program installation.

B) The program tries to open a file that would be useful but isn't
necessary for correct function. A file name is provided by the user.

For scenario A, use the OP's FileOpen function and if it throws, your
regular error handling and shutdown/reset system will deal with it. As I
said before, you should *not* add a catch just because FileOpen might
throw.

For scenario B, don't use the OP's FileOpen function. In this case, the
program is not in error, the user is in error. Your program should
expect users to make errors like that, and their errors should not cause
your program to shutdown/reset.

As I said before, a good indicator of a poorly planned/programmed system
is if there are a bunch of empty catch blocks lying around or if they
catch errors and "fix" them without re-throwing the exception (of course
the top level catch block need not re-throw.) Such code generally means
that the programmer was *expecting* the exception and using it for
normal program flow. Of course the real world is sometimes messy and
sometimes we don't have any choice, but such code is best avoided. A
thrown exception represents an unrecoverable error.

Hopefully this is more clear and less controversial.

--

John G Harris

unread,
Mar 10, 2010, 2:13:17 PM3/10/10
to
On Wed, 10 Mar 2010 at 09:47:33, in comp.lang.c++.moderated, Daniel T.
wrote:

>Seungbeom Kim <musi...@bawi.org> wrote:
>> Daniel T. wrote:
>>
>> What we're discussing here is what the program should do once it
>> ships, runs on the customer's computer and finds that it cannot open
>> the file.
>
>That can't happen in my domain (console games.) A missing file means
>that we screwed up. Same goes with a failed memory request.
<snip>

It will fail to open if some other program opens the file with exclusive
access, just a few microseconds before you try to open it.

John
--
John Harris

Daniel T.

unread,
Mar 10, 2010, 4:47:50 PM3/10/10
to
John G Harris <ne...@nospam.demon.co.uk> wrote:
> Daniel T. wrote:
> > Seungbeom Kim <musi...@bawi.org> wrote:
> > > Daniel T. wrote:
> > >
> > > What we're discussing here is what the program should do once it
> > > ships, runs on the customer's computer and finds that it cannot
> > > open the file.
> >
> > That can't happen in my domain (console games.) A missing file means
> > that we screwed up. Same goes with a failed memory request.
>
> It will fail to open if some other program opens the file with
> exclusive access, just a few microseconds before you try to open it.

I don't have to worry about some other program opening my file because
my program is the only one running.

--

Andrew

unread,
Mar 10, 2010, 10:52:12 PM3/10/10
to

> Making good design decisions about exception usage requires a
> balanced, rational appreciation of these trade offs IN THE CONTEXT OF
> THE SPECIFIC APPLICATION(S) AND DEVELOPMENT TEAM.

Indeed. For the environments and applications I typically work on, I
reckon it makes sense to use exceptions rather than error codes. But
several years back there was a SCADA app (SCADA == Supervisory Control
And Data Acquisition) I worked on where this would very probably be
the wrong thing to do, for performance reasons. Maybe the OP runs into
people that work in the performance-demanding environment of SCADA or
something similar.

Another environment where I have heard they don't like the overhead of
exceotions (even when they aren't thrown) is telecomms. If memory
serves, ACE which is sometimes used in telecoms, has or had a build
mode where you can turn exceptions off, for this reason.

Regards,

Andrew Marlow

Dan Milburn

unread,
Mar 10, 2010, 10:53:23 PM3/10/10
to
Daniel T. wrote:
> John G Harris <ne...@nospam.demon.co.uk> wrote:
>> Daniel T. wrote:
>>> Seungbeom Kim <musi...@bawi.org> wrote:
>>>> Daniel T. wrote:
>>>>
>>>> What we're discussing here is what the program should do once it
>>>> ships, runs on the customer's computer and finds that it cannot
>>>> open the file.
>>> That can't happen in my domain (console games.) A missing file means
>>> that we screwed up. Same goes with a failed memory request.
>> It will fail to open if some other program opens the file with
>> exclusive access, just a few microseconds before you try to open it.
>
> I don't have to worry about some other program opening my file because
> my program is the only one running.
>
Well, let's consider cases when this *is* possible, since it is just one
of many ways in which an error may occur which is neither the fault of
the user or the programmer, and which cannot be predicted in advance.
The only way to know for sure that a file can be opened is to try and
open it.

So, program wishes to open a file, and failure to do so is not a fatal
error. But according to you:

"A thrown exception represents an unrecoverable error."

Since you did not qualify that assertion in any way, I can only assume
you mean it to apply in every possible case, not just in your particular
domain. So, since there is a possibility of an error, but it is not
fatal, an exception cannot be thrown. You can't use the FileOpen
function described in the original post, you need a different one which
is guaranteed not to throw. Presumably this other function returns an
error code if it fails.

Going further: a library writer cannot know if an error in the library
will result in a fatal error for any program using it. So, since a
thrown exception represents an unrecoverable error, the logical
conclusion of your way of thinking is that library code cannot *ever*
throw an exception.

Which is certainly an interesting way of looking at things.

Dan

Seungbeom Kim

unread,
Mar 11, 2010, 8:15:08 AM3/11/10
to
Daniel T. wrote:
>
> When designing a program, one of the cases we have to consider is what
> to do if something goes wrong and a shutdown/reset is required. Whatever
> procedure is decided on goes in catch block(s). In other words, you put
> in catch blocks because you realize you need to do something special
> before shutdown/reset when something goes wrong, you do *not* put them
> in simply because a particular function might throw or because that
> function threw during QA testing. In the simplest case, you don't need
> to do anything before shutdown/reset and in that case there wouldn't be
> any catches in the program at all, no matter how many throws might exist.

I agree that adding exception handlers is not a mere preventive measure
or a quick cure to existing problems that should be fixed.

However, when functions advertised as being able to throw exceptions are
called, you certainly can choose to catch them in appropriate places.
You may not need to catch all exceptions, and you may just choose to
have no exception handlers because they can do very little anyway, but
in other cases not catching some exceptions may be considered as an
error and should be "fixed" by adding exception handlers.

> So we have two different scenarios on the table:
> A) The program tries to open a file that is necessary for correct
> function. This file is provided with the program and put in the correct
> place during program installation.
>
> B) The program tries to open a file that would be useful but isn't
> necessary for correct function. A file name is provided by the user.

I don't think we have a clear line between the two.

* What is the exact definition of "necessary for correct function"?
"Useful but unnecessary" seems to me like quite rare a condition, though
it certainly exists (e.g. for cache files).

* If a file is put in the correct place during program installation, is
it always necessary for correct function? If a help file was installed
but later deleted or somehow became inaccessible, is it necessary for
correct function and should its nonexistence cause the program to abort
when the user requests the help function?

* If a file name is provided by the user, is the file unnecessary for
correct function? Is the input file for "sort" or "gcc" unnecessary for
its correct function just because its filename is provided by the user?

I'm arguing that your definition of "necessary for correct function"
is vague, and that whether the filename is determined internally to the
program or comes from the user is not a useful criterion for deciding
whether "necessary for correct function" or whether to throw.

> For scenario A, use the OP's FileOpen function and if it throws, your
> regular error handling and shutdown/reset system will deal with it. As I
> said before, you should *not* add a catch just because FileOpen might
> throw.

It's not always and automatically "just because it might throw". You
may have a reasonable need to cope with exceptions. You may reasonably
choose to catch the exception, let the corresponding part of the program
fail with an error message and let the rest continue. That's what happens
when any decent program should do when the user chooses Help but it can't
open the help file; it is simply unacceptable to just unwind the stack
all the way up to main() and lose the open documents.

By the way, what is your "regular error handling and shutdown/reset
system"?

> For scenario B, don't use the OP's FileOpen function. In this case, the
> program is not in error, the user is in error. Your program should
> expect users to make errors like that, and their errors should not cause
> your program to shutdown/reset.

You're arguing that exceptions should not be used to cope with user
errors. Why not? Please don't say "Because such user errors are expected,
and exceptions are meant for unexpected cases!"... "Expected" is not
a binary attribute, and everything you write code for is, of course,
expected in some sense/to some degree. (And you know what? The most
"unexpected" and "unrecoverable" errors are even not covered by
exceptions: power failures, fires, earthquakes...)

> As I said before, a good indicator of a poorly planned/programmed system
> is if there are a bunch of empty catch blocks lying around or if they
> catch errors and "fix" them without re-throwing the exception (of course
> the top level catch block need not re-throw.) Such code generally means
> that the programmer was *expecting* the exception and using it for
> normal program flow. Of course the real world is sometimes messy and
> sometimes we don't have any choice, but such code is best avoided. A
> thrown exception represents an unrecoverable error.

That depends on the exact meaning of "(un)recoverable" error. If you
failed to open a file, you may never be able to "fix" the error so that
the file can be opened, but you may be (and should be, in many cases)
able to "recover from" the failure and let the rest of the world continue.

You seem to have a very narrow understanding of what can/should be done
in exception handlers. You almost seem to argue (or you may actually be
arguing), "Writing exception handlers means the exceptions are expected,
but exceptions are only for 'unexpected' cases, and thus you should try
not to write exception handlers at all."

I agree that abusing exceptions is bad, but your notion of the abuse
looks much wider than mine and leaves very little outside.

--
Seungbeom Kim

Daniel T.

unread,
Mar 11, 2010, 4:24:38 PM3/11/10
to
Seungbeom Kim <musi...@bawi.org> wrote:
> Daniel T. wrote:
> >
> > When designing a program, one of the cases we have to consider is what
> > to do if something goes wrong and a shutdown/reset is required. Whatever
> > procedure is decided on goes in catch block(s). In other words, you put
> > in catch blocks because you realize you need to do something special
> > before shutdown/reset when something goes wrong, you do *not* put them
> > in simply because a particular function might throw or because that
> > function threw during QA testing. In the simplest case, you don't need
> > to do anything before shutdown/reset and in that case there wouldn't be
> > any catches in the program at all, no matter how many throws might exist.
>
> I agree that adding exception handlers is not a mere preventive measure
> or a quick cure to existing problems that should be fixed.
>
> However, when functions advertised as being able to throw exceptions are
> called, you certainly can choose to catch them in appropriate places.
> You may not need to catch all exceptions, and you may just choose to
> have no exception handlers because they can do very little anyway, but
> in other cases not catching some exceptions may be considered as an
> error and should be "fixed" by adding exception handlers.

Whenever reasonable, one should stick to the "exception handling is


error handling" view. When this is done, code is clearly separated
into two categories: ordinary code and error-handling code. This
makes code more comprehensible. -- Stroustrup

> > So we have two different scenarios on the table:


> > A) The program tries to open a file that is necessary for correct
> > function. This file is provided with the program and put in the correct
> > place during program installation.
> >
> > B) The program tries to open a file that would be useful but isn't
> > necessary for correct function. A file name is provided by the user.
>
> I don't think we have a clear line between the two.

Those were the two presented so far, others can certainly be
envisioned...

> * What is the exact definition of "necessary for correct function"?
> "Useful but unnecessary" seems to me like quite rare a condition, though
> it certainly exists (e.g. for cache files).
>
> * If a file is put in the correct place during program installation, is
> it always necessary for correct function? If a help file was installed
> but later deleted or somehow became inaccessible, is it necessary for
> correct function and should its nonexistence cause the program to abort
> when the user requests the help function?

That's up to the design of the program. In the scenario portrayed, the
file is necessary and it's nonexistence should cause the program to
abort.

> * If a file name is provided by the user, is the file unnecessary for
> correct function? Is the input file for "sort" or "gcc" unnecessary for
> its correct function just because its filename is provided by the user?

Should the program do something different when it suffers an
unrecoverable error than when it can't find the file? I suspect the
answer is "yes."

> I'm arguing that your definition of "necessary for correct function"
> is vague, and that whether the filename is determined internally to the
> program or comes from the user is not a useful criterion for deciding
> whether "necessary for correct function" or whether to throw.

"Necessary for correct function" means that, if it fails your program
cannot correctly function, it must shutdown/reset.

> > For scenario A, use the OP's FileOpen function and if it throws, your
> > regular error handling and shutdown/reset system will deal with it. As I
> > said before, you should *not* add a catch just because FileOpen might
> > throw.
>
> It's not always and automatically "just because it might throw". You
> may have a reasonable need to cope with exceptions. You may reasonably
> choose to catch the exception, let the corresponding part of the program
> fail with an error message and let the rest continue. That's what happens
> when any decent program should do when the user chooses Help but it can't
> open the help file; it is simply unacceptable to just unwind the stack
> all the way up to main() and lose the open documents.

"If an exception is expected and caught so that it has no bad effects on

the behavior of the program, then how can it be an error?" -- Stroustrup

> By the way, what is your "regular error handling and shutdown/reset
> system"?

The stuff inside the catch clauses.

> > For scenario B, don't use the OP's FileOpen function. In this case, the
> > program is not in error, the user is in error. Your program should
> > expect users to make errors like that, and their errors should not cause
> > your program to shutdown/reset.
>
> You're arguing that exceptions should not be used to cope with user
> errors. Why not?

Exception handling is a less structured mechanism than local control
structures such as if and for and is often less efficient when an
exception is actually thrown. Therefore, exceptions should be used
only where the more traditional control structures are inelegant or
impossible to use. Note that the standard library offers a queue of
arbitrary elements without using exceptions. -- Stroustrup

Because "user errors" should not be unrecoverable.

> > As I said before, a good indicator of a poorly planned/programmed system
> > is if there are a bunch of empty catch blocks lying around or if they
> > catch errors and "fix" them without re-throwing the exception (of course
> > the top level catch block need not re-throw.) Such code generally means
> > that the programmer was *expecting* the exception and using it for
> > normal program flow. Of course the real world is sometimes messy and
> > sometimes we don't have any choice, but such code is best avoided. A
> > thrown exception represents an unrecoverable error.
>
> That depends on the exact meaning of "(un)recoverable" error. If you
> failed to open a file, you may never be able to "fix" the error so that
> the file can be opened, but you may be (and should be, in many cases)
> able to "recover from" the failure and let the rest of the world continue.

Now I have to ask you, how does your program recover from an
unrecoverable error? The answer is that it doesn't. If the program can
(and must) recover from the "error", it isn't really an error, it's part
of the normal flow of the program.

> You seem to have a very narrow understanding of what can/should be done
> in exception handlers. You almost seem to argue (or you may actually be
> arguing), "Writing exception handlers means the exceptions are expected,
> but exceptions are only for 'unexpected' cases, and thus you should try
> not to write exception handlers at all."

That's not what I'm arguing... If I had to distill it in one sentence, I
might say something like, "all thrown exceptions should cause the
program to shutdown/reset, possibly saving/cleaning up issues along the
way."

> I agree that abusing exceptions is bad, but your notion of the abuse
> looks much wider than mine and leaves very little outside.

There's always a little on the outside. Real life is messy and sometimes
that is reflected in software, but we shouldn't strive for making our
programs messy.

--

Daniel T.

unread,
Mar 11, 2010, 4:31:53 PM3/11/10
to
Dan Milburn <danielj...@googlemail.com> wrote:
>
> Well, let's consider cases when this *is* possible, since it is just
> one of many ways in which an error may occur which is neither the
> fault of the user or the programmer, and which cannot be predicted in
> advance. The only way to know for sure that a file can be opened is to
> try and open it.
>
> So, program wishes to open a file, and failure to do so is not a fatal
> error. But according to you:
>
> "A thrown exception represents an unrecoverable error."
>
> Since you did not qualify that assertion in any way, I can only assume
> you mean it to apply in every possible case, not just in your
> particular domain. So, since there is a possibility of an error, but
> it is not fatal, an exception cannot be thrown. You can't use the
> FileOpen function described in the original post, you need a different
> one which is guaranteed not to throw. Presumably this other function
> returns an error code if it fails.

A couple of caveats here. We don't need a function which is guaranteed
not to throw and therefore returns an error code if it fails... The
function may very well throw, just not for the reason that the file
doesn't exist, and it won't return an error code because a missing file
isn't an error in this case. What we need is a function that reports
"file not found" and doesn't consider that a *failure*.

> Going further: a library writer cannot know if an error in the library
> will result in a fatal error for any program using it. So, since a
> thrown exception represents an unrecoverable error, the logical
> conclusion of your way of thinking is that library code cannot *ever*
> throw an exception.

This is no different than having a "find" function in a library. Much
like std::find does for a value in a container, std::fopen looks for a
file in the storage system and if found returns a pointer to it,
otherwise it returns a well defined value that represents file not
found. ("File not found" is *not* an error in this case.) std::fopen
does not consider "file not found" an unrecoverable error.

"To my way of thinking," I will use fopen if I expect it to return NULL
sometimes. If a missing file results in failure of the program
(shutdown/reset) then I will throw an exception of fopen returns "not
found." (Actually I use fstreams but this point works.)

Martin B.

unread,
Mar 12, 2010, 3:01:34 PM3/12/10
to
Daniel T. wrote:
> Seungbeom Kim <musi...@bawi.org> wrote:
>> Daniel T. wrote:
>>> (....)

>> You seem to have a very narrow understanding of what can/should be done
>> in exception handlers. You almost seem to argue (or you may actually be
>> arguing), "Writing exception handlers means the exceptions are expected,
>> but exceptions are only for 'unexpected' cases, and thus you should try
>> not to write exception handlers at all."
>
> That's not what I'm arguing... If I had to distill it in one sentence, I
> might say something like, "all thrown exceptions should cause the
> program to shutdown/reset, possibly saving/cleaning up issues along the
> way."
>

If I wanted to shutdown/reset on errors, why use exceptions? I can just
call some error-handler (that may save something) and then call exit(1).
I don't need exceptions for that.

You statements seem to imply that you think that exceptions in C++ are
something fundamentally different from the Exceptions people know from
Java (or C#, or Python, or ...). Performance, usage and
non/existing-undefined-behaviour issues aside, I view them as the same
thing. I use them for errors(widely defined) than *can* be handled by
the program without a need to shutdown the program but that do not
belong to the normal control flow.

br,
Martin

John G Harris

unread,
Mar 12, 2010, 3:10:21 PM3/12/10
to
On Thu, 11 Mar 2010 at 15:24:38, in comp.lang.c++.moderated, Daniel T.
wrote:

<snip>


>That's not what I'm arguing... If I had to distill it in one sentence, I
>might say something like, "all thrown exceptions should cause the
>program to shutdown/reset, possibly saving/cleaning up issues along the
>way."

<snip>

I still don't understand why you think that exceptions *must not* be
used for any other purpose.

John
--
John Harris

Daniel T.

unread,
Mar 13, 2010, 2:52:19 AM3/13/10
to
"Martin B." <0xCDC...@gmx.at> wrote:
> Daniel T. wrote:
> > Seungbeom Kim <musi...@bawi.org> wrote:
> > > Daniel T. wrote:
> >
> > If I had to distill it in one sentence, I might say something like,
> > "all thrown exceptions should cause the program to shutdown/reset,
> > possibly saving/cleaning up issues along the way."
>
> If I wanted to shutdown/reset on errors, why use exceptions? I can
> just call some error-handler (that may save something) and then call
> exit(1). I don't need exceptions for that.

If you are writing a program using some library, and it just up and
decided to call an internal error handler and exit, I expect you would
be rather upset with the library provider, but I could be wrong. I know
I would be rather upset.

> You statements seem to imply that you think that exceptions in C++ are
> something fundamentally different from the Exceptions people know from
> Java (or C#, or Python, or ...). Performance, usage and
> non/existing-undefined-behaviour issues aside, I view them as the same
> thing. I use them for errors(widely defined) than *can* be handled by
> the program without a need to shutdown the program but that do not
> belong to the normal control flow.

"If an exception is expected and caught so that it has no bad effects on


the behavior of the program, then how can it be an error?" -- Stroustrup

--

Daniel T.

unread,
Mar 13, 2010, 3:09:12 AM3/13/10
to
John G Harris <ne...@nospam.demon.co.uk> wrote:
> Daniel T. wrote:
>
> > That's not what I'm arguing... If I had to distill it in one
> > sentence, I might say something like, "all thrown exceptions should
> > cause the program to shutdown/reset, possibly saving/cleaning up
> > issues along the way."
>
> I still don't understand why you think that exceptions *must not* be
> used for any other purpose.

"Must not" is a lot stronger than "should," especially when you stress
it... I wouldn't go that far. What I'm saying is the same thing that
Stroustrup says in section 14.5 of "The C++ Programming Language."

Exception handling is a less structured mechanism than local control
structures such as if and for and is often less efficient when an
exception is actually thrown. Therefore, exceptions should be used
only where the more traditional control structures are inelegant or
impossible to use.

...

[Use exceptions as alternate returns] can easily be overused and
lead to obscure code. Whenever reasonable, one should stick to the


"exception handling is error handling" view. When this is done,
code is clearly separated into two categories: ordinary code and
error-handling code. This makes code more comprehensible.

--

Mathias Gaunard

unread,
Mar 14, 2010, 5:38:24 AM3/14/10
to
On 13 mar, 07:52, "Daniel T." <danie...@earthlink.net> wrote:

> "If an exception is expected and caught so that it has no bad effects on
> the behavior of the program, then how can it be an error?" -- Stroustrup

Because it's a local error that was handled by some redundancy
mechanism.
Anyway, Stroustrup is not some kind of guru whose words are the law.

Seungbeom Kim

unread,
Mar 14, 2010, 5:43:48 AM3/14/10
to

"Cause the program to shutdown/reset" is a lot stronger than "error
handling", and you maintain the former while quoting the latter.

For example, if opening a file or making a network connection fails,
you should certainly handle the error but you may not necessarily cause
the program to shutdown/reset.

--
Seungbeom Kim

Dave Harris

unread,
Mar 14, 2010, 10:18:15 PM3/14/10
to
dani...@earthlink.net (Daniel T.) wrote (abridged):

> So we have two different scenarios on the table:
> A) The program tries to open a file that is necessary for correct
> function. This file is provided with the program and put in the
> correct place during program installation.
>
> B) The program tries to open a file that would be useful but isn't
> necessary for correct function. A file name is provided by the user.
> [...]

> For scenario B, don't use the OP's FileOpen function. In this case,
> the program is not in error, the user is in error. Your program should
> expect users to make errors like that, and their errors should not
> cause your program to shutdown/reset.

Here's how I usually handle that situation. At the point in the UI that
the user provides the filename, we validate it, including a check that it
exists. At this point we don't want an exception. We're half-expecting
the user to get the name wrong.

Then the filename gets handed off to some other part of the program,
which eventually uses it. At this point we do want an exception if it
doesn't exist. It's an error, but not a programmer error and not an
irrecoverable error (we recover by returning to the UI, telling the user
what happened and asking for a new filename). It's not an expected error
(it can only happen if some other process interferes with the file
between the UI and the use, which will be extremely rare).

For me, a lot of exceptions are of this sort. They almost never represent
programmer errors. They are usually resource errors. Running out of
memory is a ubiquitous one. They are not irrecoverable and should not
cause the program to shut down, but usually mean whatever the user just
tried to do can't be done.

-- Dave Harris, Nottingham, UK.

Martin B.

unread,
Mar 14, 2010, 10:18:06 PM3/14/10
to
On 13.03.2010 08:52, Daniel T. wrote:
> "Martin B."<0xCDC...@gmx.at> wrote:
>> Daniel T. wrote:
>>> Seungbeom Kim<musi...@bawi.org> wrote:
>>>> Daniel T. wrote:
>>>
>>> If I had to distill it in one sentence, I might say something like,
>>> "all thrown exceptions should cause the program to shutdown/reset,
>>> possibly saving/cleaning up issues along the way."
>>
>> If I wanted to shutdown/reset on errors, why use exceptions? I can
>> just call some error-handler (that may save something) and then call
>> exit(1). I don't need exceptions for that.
>
> If you are writing a program using some library, and it just up and
> decided to call an internal error handler and exit, I expect you would
> be rather upset with the library provider, but I could be wrong. I know
> I would be rather upset.
>

Oh sure I would be very upset. In fact I have been very upset when I had
to find a workaround to the exit(1) calls put into a (luckily
open-source) C (not ++) module we were using.

I was talking about the code we write ourselves.


>> You statements seem to imply that you think that exceptions in C++are
>> something fundamentally different from the Exceptions people knowfrom
>> Java (or C#, or Python, or ...). Performance, usage and
>> non/existing-undefined-behaviour issues aside, I view them as thesame
>> thing. I use them for errors(widely defined) than *can* be handled by
>> the program without a need to shutdown the program but that do not
>> belong to the normal control flow.
>
> "If an exception is expected and caught so that it has no bad effects on
> the behavior of the program, then how can it be an error?" --Stroustrup
>

I will take your quote and reformulate it to show what I think may be a
valid view for exceptions in C++:
"If an exception (-) is caught and so that it has no bad effect on the
outcome of the *current operation*, then how can it be an error?"

My emphasis here is that I think that exceptions are a good tool for
canceling a logical operation the program intended to take and that a
failing operation by no means should imply to terminate the whole
program. Now what such an operation could be is surely highly
individual, but my feeling is that for many people it doesn't involve
aborting the whole program.

Note how I am not arguing to use exceptions for "alternate returns" but
there are *many* shades of errors that can happen in an application and
I firmly believe that there is a class of errors that are appropriately
raised by exceptions and then *handled* - and handling doesn't imply
aborting the app for me.

cheers,
Martin

Daniel T.

unread,
Mar 14, 2010, 10:25:24 PM3/14/10
to
{ It seems that the viewpoints have already been clarified, and that the
discussion has now turned to what's best under unspecified criterions, just
reiterating earlier statements. How about an "agree to disagree"? -mod }

Seungbeom Kim <musi...@bawi.org> wrote:

> "Cause the program to shutdown/reset" is a lot stronger than "error
> handling", and you maintain the former while quoting the latter.
>
> For example, if opening a file or making a network connection fails,
> you should certainly handle the error but you may not necessarily
> cause the program to shutdown/reset.

I've already covered the first example: opening a file is not logically
different than looking for an object in a container. The inability to
find the file is not necessarily an error, it depends on context. I
suspect the second example is the same.

What should a program do if it encounters an "error"? There are only two
things it can do, (1) fix the error or (2) shutdown/reset.

In the former case, you know what can happen and the specifications for
the program have a defined method on how to handle the situation. (i.e.,
if this happens do X, otherwise do Y.) In these cases, you aren't
talking about a real error, you are simply defining an alternative
branch of execution, no different than any other "if."

Only in the latter case are you talking about an actual error. (i.e.,
this has to happen or we're screwed.)

The question here is whether we should use exceptions to replace "if"
statements.

--

Seungbeom Kim

unread,
Mar 17, 2010, 12:46:24 PM3/17/10
to
Daniel T. wrote:
> "Martin B." <0xCDC...@gmx.at> wrote:
>> You statements seem to imply that you think that exceptions in C++ are
>> something fundamentally different from the Exceptions people know from
>> Java (or C#, or Python, or ...). Performance, usage and
>> non/existing-undefined-behaviour issues aside, I view them as the same
>> thing. I use them for errors(widely defined) than *can* be handled by
>> the program without a need to shutdown the program but that do not
>> belong to the normal control flow.
>
> "If an exception is expected and caught so that it has no bad effects on
> the behavior of the program, then how can it be an error?" -- Stroustrup

You keep quoting Stroustrup without adding your interpretation, but
please be reminded that many people having discussion here with you
have read Stroustrup and have their own experience beyond that backing
up their arguments. They might feel offended if assumed otherwise and
if anyone thought that simply giving quotations would enlighten them
in a way they had not expected.

Instead of getting dogmatic about the author's literal statements,
you'd better try to understand the context and interpret what they
really mean. Try to see what he actually means as a whole in the
section. Quoting out of context can be quite misleading.

The sentence as quoted above may look like a rhetorical question meaning
"it cannot be an error" (and it seems that you understood it that way),
but my understanding is that it's simply a question that is answered by
the subsequent sentence: "Only because the programmer thinks of it as
an error and of the exception-handling mechanisms as tools for handling
errors." That actually *allows* the programmer's discretion in deciding
what is error and what is not, and allows such an exception "expected


and caught so that it has no bad effects on the behavior of the program"

to be an error depending on the programmer's decision. That is backed
up by the statement after the first example in the section, "[...] so
it is a case in which it is not entirely clear what should be considered
an error and what should not." In no way does it support your strict and
narrow notion of "exception -> error -> unrecoverable -> shutdown/reset"
(where "->" reads "must be").

--
Seungbeom Kim

Jens Schmidt

unread,
Mar 17, 2010, 11:17:39 PM3/17/10
to
Martin B. wrote:

> My emphasis here is that I think that exceptions are a good tool for
> canceling a logical operation the program intended to take and that a
> failing operation by no means should imply to terminate the whole
> program. Now what such an operation could be is surely highly
> individual, but my feeling is that for many people it doesn't involve
> aborting the whole program.
>
> Note how I am not arguing to use exceptions for "alternate returns" but
> there are *many* shades of errors that can happen in an application and
> I firmly believe that there is a class of errors that are appropriately
> raised by exceptions and then *handled* - and handling doesn't imply
> aborting the app for me.

One example that comes to my mind:
Execptions are clearly a better variant of setjmp()/longjmp(). In
database applications I wrote transactions often were spread over dozens
of functions calling each other. Whenever the database system returned
with a deadlock error, this call tree was aborted with longjmp and the
transaction restarted at the original place. Execptions would have made
this much easier.

<pseudocode language="C">
while (1)
{
if ((error = setjmp()) != 0)
{
cleanup_data();
if (error == DEADLOCK)
abort_transaction();
else
{
...
break;
]
}
initialize_data();
start_transaction();
process_data();
commit_transaction();
cleanup_data();
break;
}
return error;
</pseudocode>
--
Viele Grüße,
Jens Schmidt

mattb

unread,
Mar 18, 2010, 6:33:27 PM3/18/10
to
Having followed this discussion with interest can I posit that the
apparent lack of consistent advice on the use of exceptions is a
determining factor when people chose return codes over exceptions. It
certainly has an effect on me! As a recovering C programmer I have
often wondered why none of the introductory, or for that matter more
indepth texts I have read on C++, introduce exceptions until their
later (oftern the final) chapters, and then only provide a cursory
examination of their usage.

--

Daniel T.

unread,
Mar 19, 2010, 5:08:04 AM3/19/10
to
mattb <matthe...@l-3com.com> wrote:

> Having followed this discussion with interest can I posit that the
> apparent lack of consistent advice on the use of exceptions is a
> determining factor when people chose return codes over exceptions. It
> certainly has an effect on me! As a recovering C programmer I have
> often wondered why none of the introductory, or for that matter more
> indepth texts I have read on C++, introduce exceptions until their
> later (oftern the final) chapters, and then only provide a cursory
> examination of their usage.

I also find it interesting that when I talk about my exception use
guideline, people seem to assume that I use a lot of return error codes,
but I don't. I can't say whether it is my coding style or my domain, but
I simply don't have a problem with return codes representing errors, or
even return codes percolating up the call stack. Maybe that is why I
only use exceptions for clean shutdown...

Francis Glassborow

unread,
Mar 20, 2010, 4:26:12 AM3/20/10
to
mattb wrote:
> Having followed this discussion with interest can I posit that the
> apparent lack of consistent advice on the use of exceptions is a
> determining factor when people chose return codes over exceptions. It
> certainly has an effect on me! As a recovering C programmer I have
> often wondered why none of the introductory, or for that matter more
> indepth texts I have read on C++, introduce exceptions until their
> later (oftern the final) chapters, and then only provide a cursory
> examination of their usage.
>

Well I cannot remember where other authors introduce exceptions but I
introduce them in Chapter 4 of 'You Can Do It!' (a book for raw novices
and those just curious about what programming is) and in chapter 2 of
'You Can Program in C++' (an introductory book on C++ for those who can
do elementary programming in some language)

Martin B.

unread,
Mar 22, 2010, 8:30:00 AM3/22/10
to
mattb wrote:
> Having followed this discussion with interest can I posit that the
> apparent lack of consistent advice on the use of exceptions is a
> determining factor when people chose return codes over exceptions. It

I think an important question is whether the advice is as inconsistent
as these online discussions imply. Would be interesting to compare the
advice (in context!) some popular literature on C++ gives.
(I've checked the online TOC for "C++ Primer", Lippman/Lajoie/Moo which
is a beginners book and "Exception Handling" is the first subsection in
the advanced topics.)

> certainly has an effect on me! As a recovering C programmer I have

> often wondered ....

Maybe one key to the controversy lies in the "fact" that many people
doing C++ come from a C background and as such are averse to exceptions
because they are conceptually unknown in C. (or?) -- And because you
*can* (as opposed to should) continue to do most of your error handling
in C++ as you did in C.

cheers,
Martin

Daniel T.

unread,
Mar 22, 2010, 2:04:17 PM3/22/10
to
"Martin B." <0xCDC...@gmx.at> wrote:

> Maybe one key to the controversy lies in the "fact" that many people
> doing C++ come from a C background and as such are averse to
> exceptions because they are conceptually unknown in C. (or?) -- And
> because you *can* (as opposed to should) continue to do most of your
> error handling in C++ as you did in C.

I think everybody agrees that in C++ you should use exceptions for error handling. The only controversy I see is in how we define "error." Some people define it broadly, others define it narrowly.

Stephen Howe

unread,
Mar 26, 2010, 4:44:15 PM3/26/10
to
On Thu, 18 Mar 2010 16:33:27 CST, mattb <matthe...@l-3com.com> wrote:

>Having followed this discussion with interest can I posit that the
>apparent lack of consistent advice on the use of exceptions is a
>determining factor when people chose return codes over exceptions.

All of (do I use an exception or return code?) has bothered me for a long time.

Both bother me in that at the point where something has gone wrong, I usually
wish to return _more_ than just a bald error code
(e.g. line number, function, any other pertinent information etc). I guess an
exception is better as an object can be packaged
up and thrown.

I have now come down to the dictum

"If the error is unexpected, throw an exception otherwise return an error code."

So, running out of memory is unexpected, therefore throw an exception
Whereas reading from a file will eventually end, it is expected, so return a
code indicating that it is ended.

Stephen Howe

Mathias Gaunard

unread,
Mar 28, 2010, 4:44:57 PM3/28/10
to
On 26 mar, 22:44, Stephen Howe
<sjhoweATdialDOTpipexDOT...@giganews.com> wrote:

> Both bother me in that at the point where something has gone wrong, I usually
> wish to return _more_ than just a bald error code
> (e.g. line number, function, any other pertinent information etc). I guess an
> exception is better as an object can be packaged
> up and thrown.

That looks more like the job of logging than of exceptions.

A. McKenney

unread,
Mar 28, 2010, 5:05:32 PM3/28/10
to
I generally stay out of Holy Wars, but this statement got to me:

On Mar 22, 2:04 pm, "Daniel T." <danie...@earthlink.net> wrote:
> I think everybody agrees that in C++ you should
> use exceptions for error handling.

For sufficiently restrictive definitions of "everybody,"
I suppose so.

But you'd have to exclude me. I would not agree to
such a blanket statement, as can be seen by my response
early on in this thread.

IMAO, exceptions are like any other language construct:
facilities which have their advantages and disadvantages.
They should be used if they fit your situation better
than the alternatives. You really have to know the
requirements and constraints and then use your
judgement.

That's why we get the big bucks.

> The only controversy I see is in how we define "error."
> Some people define it broadly, others define it narrowly.

Well, if you define "error" as "something that should
throw an exception"....

Andrew

unread,
Mar 29, 2010, 3:01:02 PM3/29/10
to
On 28 Mar, 22:05, "A. McKenney" <alan_mckenn...@yahoo.com> wrote:
> I generally stay out of Holy Wars, but this statement got to me:
>
> On Mar 22, 2:04 pm, "Daniel T." <danie...@earthlink.net> wrote:
>
> > I think everybody agrees that in C++ you should
> > use exceptions for error handling.

In general I do agree with this. FWIW it is also mentioned in "Clean
Code" by Uncle Bob.

> IMAO, exceptions are like any other language construct:
> facilities which have their advantages and disadvantages.

But the main advantage of not using them is speed and the improvement
you get is not worth the disadvantages for most apps, IMHO (I
mentioned telecoms earlier in this thread as an example of where it
can matter).

It is interesting to note that this debate does not seem to occur with
other languages. You don't see people discussing exceptions versus
error codes for java. Or python. Or Eiffel. Error codes are a way of
doing things from earlier languages, such as C, and many people moved
to C++ from C. I don't think it would ever occur to a young programmer
who is just starting with java to use error codes.

I am pretty sure that Eiffel programmers wouldn't ever consider using
them either and that is an example of a language that compiles down to
native code, where presumably, people might use it for apps that
really have to perform. I am not sure about D (whcih also compiles
down to native code), since I am new to it. Maybe some D programmers
can say if the debate exists for that language.

Regards,

Andrew Marlow

Peter C. Chapin

unread,
Mar 29, 2010, 5:17:35 PM3/29/10
to
A. McKenney wrote:

> But you'd have to exclude me. I would not agree to
> such a blanket statement, as can be seen by my response
> early on in this thread.

I agree that there are times when exceptions are not necessarily the best way
of handling errors. For example exceptions are hard to analyze statically.
People interested in writing high integrity software who rely on deep static
analysis thus might want to forbid exceptions.

I'm not sure what is done by the C++ in this area, but the SPARK sublanguage
of Ada forbids exceptions for exactly this reason.

Peter

Daniel T.

unread,
Mar 30, 2010, 11:48:20 AM3/30/10
to
Andrew <marlow...@googlemail.com> wrote:
> On 28 Mar, 22:05, "A. McKenney" <alan_mckenn...@yahoo.com> wrote:
> > On Mar 22, 2:04 pm, "Daniel T." <danie...@earthlink.net> wrote:
> >
> > > I think everybody agrees that in C++ you should use exceptions for
> > > error handling.
>
> In general I do agree with this. FWIW it is also mentioned in "Clean
> Code" by Uncle Bob.
>
> > IMAO, exceptions are like any other language construct: facilities
> > which have their advantages and disadvantages.
>
> But the main advantage of not using them is speed and the improvement
> you get is not worth the disadvantages for most apps, IMHO (I
> mentioned telecoms earlier in this thread as an example of where it
> can matter).
>
> It is interesting to note that this debate does not seem to occur with
> other languages. You don't see people discussing exceptions versus
> error codes for java. Or python. Or Eiffel. Error codes are a way of
> doing things from earlier languages, such as C, and many people moved
> to C++ from C. I don't think it would ever occur to a young programmer
> who is just starting with java to use error codes.
>
> I am pretty sure that Eiffel programmers wouldn't ever consider using
> them either and that is an example of a language that compiles down to
> native code, where presumably, people might use it for apps that
> really have to perform.

Eiffel (OOSC2) is where I got the exception guideline that a catch
should re-throw. In Eiffel, the only exits from a catch block is to
retry the function or re-throw. In C++, that would mean something along
the lines of putting a while (true) loop around each try { } catch() {
}. Something like:

void fn() {
while (true) {
try {
// do stuff
return;
}
catch (...) {
// try to fix problem
if (problemNotFixed)
throw;

Stephen Howe

unread,
Mar 31, 2010, 7:50:19 PM3/31/10
to
>> Both bother me in that at the point where something has gone wrong, I usually
>> wish to return _more_ than just a bald error code
>> (e.g. line number, function, any other pertinent information etc). I guess an
>> exception is better as an object can be packaged
>> up and thrown.
>
>That looks more like the job of logging than of exceptions.

Well that is saying that at the point where something is discovered to be wrong,
it should be logged at that point (and maybe a
thin object is thrown) rather than capture all detail in a throw object. Hrrrm,
I will have to think about that.

The immediate downside is such a logger is available, if it is not, a fat object
throw is necessary until a Logger object is
available in the current scope.

Thanks for the thoughts

Stephen Howe

A. McKenney

unread,
Apr 1, 2010, 1:16:10 PM4/1/10
to
On Mar 29, 3:01 pm, Andrew <marlow.and...@googlemail.com> wrote:
> On 28 Mar, 22:05, "A. McKenney" <alan_mckenn...@yahoo.com> wrote:
...

> > IMAO, exceptions are like any other language construct:
> > facilities which have their advantages and disadvantages.
>
> But the main advantage of not using them is speed and the improvement
> you get is not worth the disadvantages for most apps, IMHO

Increased cost is not the only disadvantage
of exceptions, and, _if_ you can be sure that
the exceptions are very rarely taken,
not a big one.

Another one is that they destroy locality,
and thus make it a lot harder to figure out
the possible execution paths in
your code. Cf. Item #18 in _Exceptional_C++_.
They are a lot like "goto" (or maybe the
COME FROM statement), only worse, since at
least with "goto", you can see at compile
time where it is going to go. The matching
up of "throw" and "catch" occurs at run time.
If "goto" is Considered Harmful, why are
exceptions Considered Cool?

Another is that any code that may find itself in the
path of an exception has to be exception-safe. This
is not easy.

Finally, an uncaught exception will terminate your app,
and, in contrast to abort() or a SEGV, there's no way
to figure out where it came from.

This is not to say that exceptions are a Bad Thing.
I _do_ use them, just not anywhere near as often as
people in the C++ community seem to be recommending.

I _do_ say that your average programmer -- the kind
who writes most of the code that I see, and probably
90% of the code out there -- is not skilled enough
to use exceptions in a way that is not worse than
alternatives such as returning an error code.

> It is interesting to note that this debate does not seem to occur with
> other languages. You don't see people discussing exceptions versus
> error codes for java.

I can't speak to the other languages you mention.
My experience of Java programs is that
those who choose Java don't care about performance.
I've seen C or C++ programs replaced by Java programs
that nominally did the same job but took something like
2 to 10 times as much time to run.

This is not a criticism of Java as such, as
IIRC the design goals of Java did not include
performance as a primary objective (identical
behavior on all platforms _was_.)

It _is_ a criticism of the attitude that Java
should be used for everything.

I also have to say that my experience of
using Java apps and API's is that they seem
to get "uncaught exception" errors on a regular
basis. So Java exceptions, at least, don't
seem to be any more foolproof than C++ exceptions.

Martin B.

unread,
Apr 2, 2010, 11:57:05 AM4/2/10
to
A. McKenney wrote:
> On Mar 29, 3:01 pm, Andrew <marlow.and...@googlemail.com> wrote:
>> On 28 Mar, 22:05, "A. McKenney" <alan_mckenn...@yahoo.com> wrote:
> ...
>>> IMAO, exceptions are like any other language construct:
>>> facilities which have their advantages and disadvantages.
>> But the main advantage of not using them is speed and the improvement
>> you get is not worth the disadvantages for most apps, IMHO
>
> Increased cost is not the only disadvantage
> of exceptions, (...)

>
> Another one is that they destroy locality,
> and thus make it a lot harder to figure out
> the possible execution paths in
> your code. Cf. Item #18 in _Exceptional_C++_.
> They are a lot like "goto" (or maybe the
> COME FROM statement), only worse, since at
> least with "goto", you can see at compile
> time where it is going to go. The matching
> up of "throw" and "catch" occurs at run time.
> If "goto" is Considered Harmful, why are
> exceptions Considered Cool?
>

Hmmm ... sounds a bit like oversimplification to me. I thought goto is
considered "evil" because it can be used to write completely
unstructured code whereas exceptions may not be handled locally but are
still pretty structured IMHO.

> Another is that any code that may find itself in the
> path of an exception has to be exception-safe. This
> is not easy.
>

This is a good argument. Writing exception safe code is hard *in
practice*. Still, I think it's worth learning because you pick up a lot
of other useful stuff on the way.

> Finally, an uncaught exception will terminate your app,
> and, in contrast to abort() or a SEGV, there's no way
> to figure out where it came from.
>

I work on Windows and handling an uncaught exception is nearly the same
as abort() and SEGV there. So this argument is wrong at least for the
Windows platform. (Specifically: It's possible to generate a minidump or
invoke a debugger in all three cases.)

> (...)


> I _do_ say that your average programmer -- the kind
> who writes most of the code that I see, and probably
> 90% of the code out there -- is not skilled enough
> to use exceptions in a way that is not worse than
> alternatives such as returning an error code.
>

Another semi-good point. I would say that in those cases where
exceptions can be considered (due to the exceptional nature of the code
path) the average programmer will mess up the error-return variation too
because it - being exceptional - won't be properly tested.

>> It is interesting to note that this debate does not seem to occur with
>> other languages. You don't see people discussing exceptions versus
>> error codes for java.
>
> I can't speak to the other languages you mention.
> My experience of Java programs is that
> those who choose Java don't care about performance.
> I've seen C or C++ programs replaced by Java programs
> that nominally did the same job but took something like
> 2 to 10 times as much time to run.
>
> This is not a criticism of Java as such, as

> (...) It _is_ a criticism of the attitude that Java


> should be used for everything.
>

Java was introduced as an example (at least by me) because it is a)
rather ubiquitous and b) because exceptions are core to java. Not
because of any performance characteristics.


> I also have to say that my experience of
> using Java apps and API's is that they seem
> to get "uncaught exception" errors on a regular
> basis. So Java exceptions, at least, don't
> seem to be any more foolproof than C++ exceptions.
>

They are a lot more foolproof because the behaviour is always
well-defined, and you get a stack-trace for free.
This is one of the points that make C++ exceptions less useful that Java
ones. If I catch a Java (or .NET) exception, I have a full stack-trace
for logging but if I *catch* a C++ exception all information between the
throw and the catch is lost.

Anyway - I'm not convinced that the "uncaught exception" argument can be
used at all, since an uncaught exception seems the same as an unhandled
error-return-code: both result in (different) undesired program behaviour.

cheers,
Martin

A. McKenney

unread,
Apr 2, 2010, 6:04:17 PM4/2/10
to
On Apr 2, 11:57 am, "Martin B." <0xCDCDC...@gmx.at> wrote:
> A. McKenney wrote:
...

> > Increased cost is not the only disadvantage
> > of exceptions, (...)
>
> > Another one is that they destroy locality,
> > and thus make it a lot harder to figure out
> > the possible execution paths in
> > your code. Cf. Item #18 in _Exceptional_C++_.
> > They are a lot like "goto" (or maybe the
> > COME FROM statement), only worse, since at
> > least with "goto", you can see at compile
> > time where it is going to go. The matching
> > up of "throw" and "catch" occurs at run time.
> > If "goto" is Considered Harmful, why are
> > exceptions Considered Cool?
>
> Hmmm ... sounds a bit like oversimplification to me. I thought goto is
> considered "evil" because it can be used to write completely
> unstructured code whereas exceptions may not be handled locally but are
> still pretty structured IMHO.

But _why_ is "structured code" considered "good"?
Because it simplifies the analysis of flow of control.
Back in the day, they were thinking in terms of
correctness proofs, but it also applies to avoiding
and/or finding bugs when looking at code.

IMHO, exceptions are _not_ structured, because
they violate the principle of the Structured
Programming constructs: that one should be
able to see the possible execution paths
of a chunk of code by looking at the control
structures/blocks.

Actually, a number of people believed that
"return" was a violation of Structured Programming,
and IIRC, Nikolas Wirth devised Modula-2 (and Pascal?)
with no return statement.

> > I also have to say that my experience of
> > using Java apps and API's is that they seem
> > to get "uncaught exception" errors on a regular
> > basis. So Java exceptions, at least, don't
> > seem to be any more foolproof than C++ exceptions.
>
> They are a lot more foolproof because the behaviour is always
> well-defined, and you get a stack-trace for free.
> This is one of the points that make C++ exceptions less useful that Java
> ones. If I catch a Java (or .NET) exception, I have a full stack-trace
> for logging but if I *catch* a C++ exception all information between the
> throw and the catch is lost.

AFAIK, uncaught exceptions are considered a Bad Thing
in both C++ and Java. My point was that professional
(=paid) Java programmers are shipping code (to us,
at least) that gets uncaught exceptions. (Heck,
my _Blackberry_ gets uncaught exception errors!)
So it is not as though Java has made exceptions all that
foolproof.

One difference (correct me if I'm wrong!) is that
Jave _requires_ exception specifications, so
you can at least see from the function prototype
what exceptions you can get. This makes it a
little more like error codes, in that there
is something in the function signature.
Unfortunately, this was not an option when
they put exceptions into C++ .

Öö Tiib

unread,
Apr 3, 2010, 4:35:01 PM4/3/10
to
On 1 apr, 20:16, "A. McKenney" <alan_mckenn...@yahoo.com> wrote:
> On Mar 29, 3:01 pm, Andrew <marlow.and...@googlemail.com> wrote:
>
> > On 28 Mar, 22:05, "A. McKenney" <alan_mckenn...@yahoo.com> wrote:
> ...
> > > IMAO, exceptions are like any other language construct:
> > > facilities which have their advantages and disadvantages.
>
> > But the main advantage of not using them is speed and the improvement
> > you get is not worth the disadvantages for most apps, IMHO
>
> Increased cost is not the only disadvantage
> of exceptions, and, _if_ you can be sure that
> the exceptions are very rarely taken,
> not a big one.
>
> Another one is that they destroy locality,
> and thus make it a lot harder to figure out
> the possible execution paths in
> your code. Cf. Item #18 in _Exceptional_C++_.
> They are a lot like "goto" (or maybe the
> COME FROM statement), only worse, since at
> least with "goto", you can see at compile
> time where it is going to go. The matching
> up of "throw" and "catch" occurs at run time.
> If "goto" is Considered Harmful, why are
> exceptions Considered Cool?

Error codes and error states are often reasonable tools. Exception is
often reasonable tool. What are the reasonable excuses to use that
goto? Only to tidy up too massive error-codes-that-never-happen-
checking-mess?

> Another is that any code that may find itself in the
> path of an exception has to be exception-safe. This
> is not easy.

Exception safety level is anyway something that you have to specify,
promise, require and achieve these days. Otherwise it is like not
using threads in your code and then pretending that these do not exist
in whole system. It may happen that neither does exist in that
embedded system under development, but that is rare case.

> Finally, an uncaught exception will terminate your app,
> and, in contrast to abort() or a SEGV, there's no way
> to figure out where it came from.

It is a crash so it is up to platform what level of information it
provides on such crash. Typical: Her cellphone crashed silently and
rebooted at night. That turned off the alarm-clock. So she was late to
work. Now at lunch you try to tell her about how that abort() or a
SEGV there was good.

> This is not to say that exceptions are a Bad Thing.
> I _do_ use them, just not anywhere near as often as
> people in the C++ community seem to be recommending.

Assert/abort is like not letting anyone to work when your requirements
for doing your job are not met. Return code/error state is like
putting a sign with 'false' or '-2' onto your desk when you cannot do
your job. Exception is like immediately and with enough detail
complaining exactly why you refuse to do what was asked. So abort() is
often too harsh and error state too subtle and that leaves exception
as most flexible.

> I _do_ say that your average programmer -- the kind
> who writes most of the code that I see, and probably
> 90% of the code out there -- is not skilled enough
> to use exceptions in a way that is not worse than
> alternatives such as returning an error code.

Exceptions are one tool to achieve the goals of error handling. Error
handling is major part of any code. For such major aspect there should
be a policy established and agreed upon when gathering the team. When
the policy is established then average Joe picks it up rather quickly.
Well established error handling policy makes the code simpler to read
and easier to understand. Skilled people are so precise even about
white space and naming conventions, so why not about error handling?
What does always hurt is anarchy, no matter how experienced are the
team members.

> > It is interesting to note that this debate does not seem to occur with
> > other languages. You don't see people discussing exceptions versus
> > error codes for java.
>
> I can't speak to the other languages you mention.
> My experience of Java programs is that
> those who choose Java don't care about performance.
> I've seen C or C++ programs replaced by Java programs
> that nominally did the same job but took something like
> 2 to 10 times as much time to run.

Exceptions are thrown rarely despite the code is full of 'throw's. The
fact that errors are handled does not mean they happen 10000 times in
a cycle. It is maybe 3 or 10 times within a hour. How that can hinder
your applications performance? It just helps to guarantee that it does
not crash 3 or 10 times per hour.

Martin B.

unread,
Apr 3, 2010, 4:36:39 PM4/3/10
to
On 03.04.2010 00:04, A. McKenney wrote:
> On Apr 2, 11:57 am, "Martin B."<0xCDCDC...@gmx.at> wrote:
>> A. McKenney wrote:
> ....

>>> I also have to say that my experience of
>>> using Java apps and API's is that they seem
>>> to get "uncaught exception" errors on a regular
>>> basis. So Java exceptions, at least, don't
>>> seem to be any more foolproof than C++ exceptions.
>>
>> They are a lot more foolproof because the behaviour is always
>> well-defined, and you get a stack-trace for free.
>> This is one of the points that make C++ exceptions less useful that Java
>> ones. If I catch a Java (or .NET) exception, I have a full stack-trace
>> for logging but if I *catch* a C++ exception all information between the
>> throw and the catch is lost.
>
> AFAIK, uncaught exceptions are considered a Bad Thing

So is any ACCESS_VIOLATION/segfault. Just because dereferencing an
invalid pointer value in C++ will (likely) crash my program doesn't mean
I won't use pointers. At least uncaught exceptions are kind-of defined
behaviour.

> in both C++ and Java. My point was that professional
> (=paid) Java programmers are shipping code (to us,
> at least) that gets uncaught exceptions. (Heck,
> my _Blackberry_ gets uncaught exception errors!)
> So it is not as though Java has made exceptions all that
> foolproof.
>

As stated above. It's not about the fool-proove-ness of exceptions.
Other things will crash a program. (And paid programmers are just as
crappy as unpaid ones.)
To give a Java example: If you access a null-reference, you will get a
NullPointerException that you can handle or not. If it's not handled the
program terminates. Cause and Effect -> Bug and Unhandled Exception.

> One difference (correct me if I'm wrong!) is that
> Jave _requires_ exception specifications, so
> you can at least see from the function prototype

> what exceptions you can get. (...)

Java has checked and unchecked exceptions and many are unchecked.
And what I gather is that they learned that the checked ones don't work
out too well.

cheers,
Martin

Mathias Gaunard

unread,
Apr 3, 2010, 4:33:56 PM4/3/10
to
On 2 avr, 23:04, "A. McKenney" <alan_mckenn...@yahoo.com> wrote:

> One difference (correct me if I'm wrong!) is that
> Jave _requires_ exception specifications, so
> you can at least see from the function prototype
> what exceptions you can get.

It does, but you can bypass it by deriving your exception from a
specific type, or from using the base type of all exceptions in the
throws clause of the function declaration.


> This makes it a
> little more like error codes, in that there
> is something in the function signature.
> Unfortunately, this was not an option when
> they put exceptions into C++ .

Checked exceptions don't really work anyway. It's more of an annoyance
than anything else.
Consider a generic wrapper or container. It must throw whatever it is
holding does.

Joshua Maurice

unread,
Apr 5, 2010, 8:18:48 PM4/5/10
to
On Apr 3, 1:33 pm, Mathias Gaunard <loufo...@gmail.com> wrote:
> On 2 avr, 23:04, "A. McKenney" <alan_mckenn...@yahoo.com> wrote:
>
> > One difference (correct me if I'm wrong!) is that
> > Jave _requires_ exception specifications, so
> > you can at least see from the function prototype
> > what exceptions you can get.
>
> It does, but you can bypass it by deriving your exception from a
> specific type, or from using the base type of all exceptions in the
> throws clause of the function declaration.
>
> > This makes it a
> > little more like error codes, in that there
> > is something in the function signature.
> > Unfortunately, this was not an option when
> > they put exceptions into C++ .
>
> Checked exceptions don't really work anyway. It's more of an annoyance
> than anything else.
> Consider a generic wrapper or container. It must throw whatever it is
> holding does.

Statically checked exceptions (as Java currently implements) are not
terribly useful, I agree.

However, let me take this opportunity to plug my own idea on checked
exceptions. Allow each function to have a statically_throws
declaration or no statically_throws declaration. A function without a
statically_throws declaration is a propagator; it acts as if it had a
statically_throws declaration exactly of what it actually throws. When
the compiler compiles down each function, it adds metadata to the
function of its source-code-declared statically_throws declaration (or
lack thereof) and what it actually throws. The compiler and linker can
then use this information to statically check source-code-declared
statically_throws declarations at link time (and some at compile
time).

For example, generic containers would be written without
statically_throws declarations. It would just propagate whatever
exceptions its contained elements can statically throw.

This idea is based on the observation that you mostly only want to
specify a statically checked throws declaration at "interfaces"
between "components". In the internals, it's irrelevant clutter, but
when you're using someone else's API, it matters, and when determining
the correctness of your own code and API, statically checked exception
throws declarations would be a great tool.

Unfortunately this idea is doomed for the same reason that extern
template is doomed: it would require linker support beyond the C
object model. Then there's also the problems of how this would
interact with dlls which I have not thought through, and which the C++
standard committee cannot ignore.

gas...@hotmail.com

unread,
Apr 7, 2010, 12:49:41 PM4/7/10
to
On 15 mrt, 04:25, "Daniel T." <danie...@earthlink.net> wrote:
> > For example, if opening a file or making a network connection fails,
> > you should certainly handle the error but you may not necessarily
> > cause the program to shutdown/reset.
>
> I've already covered the first example: opening a file is not logically
> different than looking for an object in a container. The inability to
> find the file is not necessarily an error, it depends on context. I
> suspect the second example is the same.

Boost.Filesystem uses exceptions when a file cannot be accessed. This
broked my use, in which I just iterated over all files to get a global
impression how large the directory was (see
http://article.gmane.org/gmane.comp.lib.boost.user/54721). For some
conditions an inaccessable file may be critical, here it was not that
important.

With call / return type of error reporting a missed error may be a
cosmetic or a bad thing; with exceptions an overlooked one will
certainly end ur program.

0 new messages