473,513 Members | 2,684 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

When to use exceptions

What I want to do is to read a 32-bit unsigned integer (let's call that
u32) in little-endian form from an fstream. Would it be better if my
function went like this:

// returns false if an error occurs reading the value
bool read(std::fstream& stream, u32& value);

or this:

u32 read(std::fstream& stream) throw(FileReadingException);

In general, what are some good guidelines for when something like the
first is preferred over something like the second, and vice-versa?

--
I am only a mirage.
Jul 23 '05 #1
13 1660
* kelvSYC:
What I want to do is to read a 32-bit unsigned integer (let's call that
u32) in little-endian form from an fstream. Would it be better if my
function went like this:

// returns false if an error occurs reading the value
bool read(std::fstream& stream, u32& value);

or this:

u32 read(std::fstream& stream) throw(FileReadingException);
Given only these two to choose from:

the first and only the first.

But also provide a throwing version like the second but without exception
specification.

In general, what are some good guidelines for when something like the
first is preferred over something like the second


Always. Exception specifications are very impractical and misleading in
C++. There are only a few forms that are acceptable, in certain contexts.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #2
> > // returns false if an error occurs reading the value
bool read(std::fstream& stream, u32& value);

or this:

u32 read(std::fstream& stream) throw(FileReadingException);


Given only these two to choose from:

the first and only the first.

But also provide a throwing version like the second but without exception
specification.


So a comprimise like so:

// throws exception if an error occurs reading the value, but is not
// specified in the prototype
u32 read(std::fstream& stream);

would be acceptable C++ style then?

--
I am only a mirage.
Jul 23 '05 #3
* kelvSYC:
// returns false if an error occurs reading the value
bool read(std::fstream& stream, u32& value);

or this:

u32 read(std::fstream& stream) throw(FileReadingException);


Given only these two to choose from:

the first and only the first.

But also provide a throwing version like the second but without exception
specification.


So a comprimise like so:

// throws exception if an error occurs reading the value, but is not
// specified in the prototype
u32 read(std::fstream& stream);

would be acceptable C++ style then?


1. What if you need i32 result, double result, and so forth?

2. What if you'd like to use this for a stream that's not an fstream?

3. The earlier quandary seems to indicate a non-throwing version can
come in handy, and there's no need to exclude it.

So perhaps

template< typename T >
void throwIf0( T nonzero, char const diagnostic[] )
{
if( !nonzero ){ throw std::runtime_error( diagnostic ); }
}

bool readBinary( std::istream& stream, u32& result ){ ... }

u32 u32FromBinary( std::istream& stream )
{
u32 result;
throwIf0( read( stream, result ), "my useful diagnostic" );
return result;
}

For text I'd just read text strings and convert them to whatever
they represent, because such functions are much cleaner and more
reusable, and because stream based text-to-other conversion is not
well-defined in C++ (the interface is there, the definition not).

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #4
> What I want to do is to read a 32-bit unsigned integer (let's call that
u32) in little-endian form from an fstream. Would it be better if my
function went like this:

// returns false if an error occurs reading the value
bool read(std::fstream& stream, u32& value);

or this:

u32 read(std::fstream& stream) throw(FileReadingException);


I prefer to throw when an error occurs. This ensures me that the execution
of the calling function stops. Without throwing I might forget handling the
error condition and such errors are hard to find during test.

Niels Dybdahl
Jul 23 '05 #5
On Mon, 6 Jun 2005 07:22:36 UTC, "Niels Dybdahl" <nd*@esko-graphics.com>
wrote:

<snip>
I prefer to throw when an error occurs. This ensures me that the execution
of the calling function stops. Without throwing I might forget handling the
error condition and such errors are hard to find during test.

Niels Dybdahl


My preference, as the designer and developer of a function, is to provide
adequate documentation about the behavior and abilities of said function.
As the user of functions that others have developed, I want to see such
documentation as well.

My reasoning is that at any location in a given fragment of code, an
error may occur. Some errors are more likely than others. Exception
based error reporting enforces the user to wrap all code levels with
appropriate exception handling code. This must be done often enough
that the user can actually find and correct the cause of an error
when it occurs. For any given level of functionality, there are many
possible errors to report -- whether they may be from exceptions or
other known sources.

Given a well documented interface, the user can then decide what
is an appropriate use for their needs. This includes handling
unexpected conditions.

Users need to handle errors at a reasonable level. Your preference
to use an exception to report "an expected file error" may be appropriate
for one developer and not another.

My preference for using exceptions is to use them very sparingly
and with good cause. Before exceptions were common, return codes
and other methods were commonplace. The user had to decide at what level
to check for these unexpected conditions. Exceptions give us a different
method of reporting errors. Now users are faced with handling both
methods all of the time. Your code could be quite complicated for
handling information (expected and unexpected behavior) for any non-trivial
function. When designing interfaces, please make it easy to understand
what the expected behavior is. I should be able to use nearly all
interfaces by reading just the interface documentation (.h and other files).
You should make it easy for the user to handle all errors and behaviors
appropriately. That has different meanings for different environments.
So, consider your user base when designing an interface.

Your suggestion that the interface provide both non-exception and
exception based functions is a good one. However, when that function
is non-trivial, you may find that writing both versions at a level that
can handle all errors appropriately may be a daunting task. The two
functions may not even look the same. Keeping them in-sync could be
difficult.

David
Jul 23 '05 #6
Niels Dybdahl wrote:
What I want to do is to read a 32-bit unsigned integer (let's call that
u32) in little-endian form from an fstream. Would it be better if my
function went like this:

// returns false if an error occurs reading the value
bool read(std::fstream& stream, u32& value);

or this:

u32 read(std::fstream& stream) throw(FileReadingException);


I prefer to throw when an error occurs. This ensures me that the execution
of the calling function stops. Without throwing I might forget handling
the error condition and such errors are hard to find during test.


However, if the calling code needs to know exactly where the reading failed,
it leads to excessive typing:

struct somestruct
{
long a;
long b;
long c;
};

//...

somestruct s;
try
{
s.a = read(stream);
}
catch (FileReadingException& ex)
{
//... whatever
return; // or throw or whatever
}

try
{
s.b = read(stream);
}
catch (FileReadingException& ex)
{
//... whatever
return; // or throw or whatever
}

try
{
s.c = read(stream);
}
catch (FileReadingException& ex)
{
//... whatever
return; // or throw or whatever
}

//...

Jul 23 '05 #7
kelvSYC wrote:
// returns false if an error occurs reading the value
bool read(std::fstream& stream, u32& value);

or this:

u32 read(std::fstream& stream) throw(FileReadingException);

In general, what are some good guidelines for when something like the
first is preferred over something like the second, and vice-versa?


IMO that depends of the file format. If, for example, you are reading until
eof, the first way is best. If the format is fixed, and you know how much
data is in the file and a failure to read means that the file is corrupt or
unreadable, the second way allows cleaner code.

--
Salu2
Jul 23 '05 #8
Rolf Magnus wrote:
However, if the calling code needs to know exactly where the reading
failed, it leads to excessive typing:

struct somestruct
{
long a;
long b;
long c;
};

//...

somestruct s;
try
{
s.a = read(stream);
}
catch (FileReadingException& ex)
{
//... whatever
return; // or throw or whatever
}

try
{
s.b = read(stream);
}
catch (FileReadingException& ex)
{
//... whatever
return; // or throw or whatever
}


You can do something like that:

void readsome ( ..... , StatReadSome & stat)
{
.....
stat= ReadSomeNothing;
s.a= read (stream);
stat= ReadSome_a;
s.b= read (stream);
stat= ReadSome_b;
....
}

--
Salu2
Jul 23 '05 #9
> > I prefer to throw when an error occurs. This ensures me that the
execution
of the calling function stops. Without throwing I might forget handling
the error condition and such errors are hard to find during test.
However, if the calling code needs to know exactly where the reading

failed, it leads to excessive typing:

struct somestruct
{
long a;
long b;
long c;
};

//...

somestruct s;
try
{
s.a = read(stream);
}
catch (FileReadingException& ex)
{
//... whatever
return; // or throw or whatever
}

try
{
s.b = read(stream);
}
catch (FileReadingException& ex)
{
//... whatever
return; // or throw or whatever
}

try
{
s.c = read(stream);
}
catch (FileReadingException& ex)
{
//... whatever
return; // or throw or whatever
}

//...


No. You can just do:

s.a = read(stream);

s.b = read(stream);

s.c = read(stream);

No error checking code means that there is much less error checking code to
test. How often do you make systematic test of your error checking code ?

Niels Dybdahl
Jul 23 '05 #10
Niels Dybdahl wrote:
> I prefer to throw when an error occurs. This ensures me that the execution > of the calling function stops. Without throwing I might forget handling
> the error condition and such errors are hard to find during test.
However, if the calling code needs to know exactly where the reading
failed, it leads to excessive typing:

struct somestruct
{
long a;
long b;
long c;
};

//...

somestruct s;
try
{
s.a = read(stream);
}
catch (FileReadingException& ex)
{
//... whatever
return; // or throw or whatever
}

try
{
s.b = read(stream);
}
catch (FileReadingException& ex)
{
//... whatever
return; // or throw or whatever
}

try
{
s.c = read(stream);
}
catch (FileReadingException& ex)
{
//... whatever
return; // or throw or whatever
}

//...


No. You can just do:

s.a = read(stream);

s.b = read(stream);

s.c = read(stream);


And how do I know whether s.c really contains a value read from the file?
No error checking code means that there is much less error checking code
to test.
And it leads to programs that print messages like "There was some error."
without letting the user know what the exact error actually was, because
that information got lost due to the missing error checking code.
How often do you make systematic test of your error checking code
?


You mean, you don't test how your program reacts to various errors in the
input data?

Jul 23 '05 #11
> > No. You can just do:

s.a = read(stream);

s.b = read(stream);

s.c = read(stream);
And how do I know whether s.c really contains a value read from the file?


It does. If an error occurred, the execution is breaked by an exception.
No error checking code means that there is much less error checking code
to test.


And it leads to programs that print messages like "There was some error."
without letting the user know what the exact error actually was, because
that information got lost due to the missing error checking code.
How often do you make systematic test of your error checking code
?


You mean, you don't test how your program reacts to various errors in the
input data?


No I do not mean that. I mean: do you go through your sourcecode to locate
all your error checking code and create test cases so that each error
checking code is tested for correct behaviour ? It is not nice to send out
an application where numerous code lines have never been executed.

Niels Dybdahl

Jul 23 '05 #12
Niels Dybdahl wrote:
> No. You can just do:
>
> s.a = read(stream);
>
> s.b = read(stream);
>
> s.c = read(stream);
And how do I know whether s.c really contains a value read from the file?


It does. If an error occurred, the execution is breaked by an exception.


Ok, bad example. What about s.b then? If an exception during reading s.c is
thrown, s.b contains a valid value, if an exception is thrown earlier, it
doesn't.
> No error checking code means that there is much less error checking
> code to test.


And it leads to programs that print messages like "There was some error."
without letting the user know what the exact error actually was, because
that information got lost due to the missing error checking code.
> How often do you make systematic test of your error checking code
> ?


You mean, you don't test how your program reacts to various errors in the
input data?


No I do not mean that. I mean: do you go through your sourcecode to locate
all your error checking code and create test cases so that each error
checking code is tested for correct behaviour ?


No.
It is not nice to send out an application where numerous code lines have
never been executed.


And you think it's better to leave that code out completely?

Jul 23 '05 #13
> >> > No. You can just do:
>
> s.a = read(stream);
>
> s.b = read(stream);
>
> s.c = read(stream);

And how do I know whether s.c really contains a value read from the
file?
It does. If an error occurred, the execution is breaked by an exception.
Ok, bad example. What about s.b then? If an exception during reading s.c

is thrown, s.b contains a valid value, if an exception is thrown earlier, it
doesn't.


So if an exception occurs, you have to treat all values gained in this
functionality as invalid. Code designed on returned error values have exact
the same problem. For local variables it is not a problem as they are
automatically destructed and removed. For global variables you will always
have the problem: What to do if the structure is only partly created due to
an error ?
No I do not mean that. I mean: do you go through your sourcecode to locate all your error checking code and create test cases so that each error
checking code is tested for correct behaviour ?


No.
It is not nice to send out an application where numerous code lines have
never been executed.


And you think it's better to leave that code out completely?


If the error still can be handled, as it can with exceptions, then yes. Deep
into the "read" function there are still error checking code that can throw
and I hope that the author of that function has tested that. At a high level
I would have a try/catch block that catches all errors and reports the
errors to the operator or to a log. I might have a few try/catch blocks for
cleaning up, but I try to avoid that as much as possible and use destructors
instead.
This has two advantages: Less untested code and my code consists of less
error handling, so that is easier to read and maintain.

Niels Dybdahl
Jul 23 '05 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
1529
by: John J. Lee | last post by:
Bare "except:", with no exception specified, is nasty because it can easily hide bugs. There is a case where it seemed useful to me in the past. Now it seems like a bad idea to me (but I think...
10
1528
by: Jakob Bieling | last post by:
Hi, somehow the prejudice of exceptions being rather slow (compared to, ie. returning an error value and checking that) keeps sticking around .. at least around me. I guess this is also why I...
8
2235
by: cat | last post by:
I had a long and heated discussion with other developers on my team on when it makes sense to throw an exception and when to use an alternate solution. The .NET documentation recommends that an...
5
1477
by: Joris Zwaenepoel | last post by:
Hi all, I don't think a solution exists, but maybe there is some option in Visual Studio that I do not know about. When developping (or debugging), I like to set the "exceptions" option to...
4
1839
by: Steve | last post by:
I have read a couple articles online, read my Jesse Liberty book but I am still confused as to just what the best practices are for using exceptions. I keep changing how I'm working with them and...
22
16885
by: dvestal | last post by:
Suppose I have this: class C { public delegate void MyEventHandler(); public event MyEventHandler MyEvent; public void foo() { MyEvent(); // NullReferenceException? } }
2
5281
by: pillappa | last post by:
Hi, I am hitting this error consistently and don't know why it's happening. I would like to define all exceptions for my project in one file and use them across the project. Here's a sample - ...
8
2430
by: Olivier BESSON | last post by:
Hello, VB.NET 1.1 IIS 6 I'm developping a winform client app of a web service of mine. I used to set the IDE with "halt in debugger" on "common language runtime exceptions". Every time i...
9
1920
by: =?Utf-8?B?UmFq?= | last post by:
How do I know which methods will throw exception when I am using FCL or other third party .Net library? I am developer of mostly native Windows applications and now .Net. After working few...
0
7257
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
7379
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
1
7098
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
1
5084
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
4745
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3232
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
3221
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1591
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
0
455
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.