Calling function that may throw an exception

E

Eric Lilja

Hello, I'm working with a hash table that is encapsulated in a class. One of
its member functions insert() throws an exception
if the insertion fails (for example, if the value was already present in the
hash table). Now I have client code that looks like this:

bool exception_thrown = false;

try
{
hash_table.insert(some_value);
}
catch(const std::runtime_error& e)
{
std::cerr << e.what() << std::endl;

exception_thrown = true;
}

if(!exception_thrown)
{
std::cout << some_value << " successfully inserted." << std::endl; /* For
debugging purposes, it would be nice to see position here */
}

Using the flag variable exception_thrown strikes me as a bit ugly...how
should I deal with this? If I'm calling a function that
may throw an exception I want to catch that exception. I can change the hash
table class itself if I need to..maybe the insert()
member function should return some error code instead but runtime_error
seems a bit more convenient since it can (should I think)
contain a description of the error. Please advise.

/ Eric
 
V

Victor Bazarov

Eric said:
Hello, I'm working with a hash table that is encapsulated in a class. One of
its member functions insert() throws an exception
if the insertion fails (for example, if the value was already present in the
hash table). Now I have client code that looks like this:

bool exception_thrown = false;

try
{
hash_table.insert(some_value);
}
catch(const std::runtime_error& e)
{
std::cerr << e.what() << std::endl;

exception_thrown = true;
}

if(!exception_thrown)
{
std::cout << some_value << " successfully inserted." << std::endl; /* For
debugging purposes, it would be nice to see position here */
}

Using the flag variable exception_thrown strikes me as a bit ugly...how
should I deal with this? If I'm calling a function that
may throw an exception I want to catch that exception. I can change the hash
table class itself if I need to..maybe the insert()
member function should return some error code instead but runtime_error
seems a bit more convenient since it can (should I think)
contain a description of the error. Please advise.

There was a discussion here recently "Arguments *Against* Exception Use".
Check it out. There was the note by Herb Sutter reminding us that one
shouldn't confuse normal functionality (and processing thereof) with
exceptional situations. If your hash table is _allowed_ to indicate that
insertion didn't happen and that's normal, then it has to be a return code
and not an exception. Something like that, anyway.

V
 
A

Alf P. Steinbach

* Victor Bazarov:
There was a discussion here recently "Arguments *Against* Exception Use".
Check it out. There was the note by Herb Sutter reminding us that one
shouldn't confuse normal functionality (and processing thereof) with
exceptional situations. If your hash table is _allowed_ to indicate that
insertion didn't happen and that's normal, then it has to be a return code
and not an exception. Something like that, anyway.

It's very easy to have both.

In terms of both efficiency and simplicity the best is to build the
exception-throwing one as a wrapper around the return-code one.

But I remember I argued at least halfway successfully once for doing
it the opposite way when a higher layer calls a lower layer of software.
The reason for that is that what is an exception at a lower layer
(e.g. unable to send mail) at some higher level becomes an expected and
quite normal thing (e.g. report that to the user). But the argument is
mostly for trolling purposes, because the assumption that both these
layers are involved in the same design is not a well-founded one... ;-)
 
J

John Harrison

Eric Lilja said:
Hello, I'm working with a hash table that is encapsulated in a class. One
of its member functions insert() throws an exception
if the insertion fails (for example, if the value was already present in
the hash table). Now I have client code that looks like this:

bool exception_thrown = false;

try
{
hash_table.insert(some_value);
}
catch(const std::runtime_error& e)
{
std::cerr << e.what() << std::endl;

exception_thrown = true;
}

if(!exception_thrown)
{
std::cout << some_value << " successfully inserted." << std::endl; /*
For debugging purposes, it would be nice to see position here */
}

Using the flag variable exception_thrown strikes me as a bit ugly...how
should I deal with this?

Well you can certainly simplify the code, no flag is needed

try
{
hash_table.insert(some_value);
std::cout << some_value << " successfully inserted." << std::endl;
}
catch(const std::runtime_error& e)
{
std::cerr << e.what() << std::endl;
}
If I'm calling a function that
may throw an exception I want to catch that exception. I can change the
hash table class itself if I need to..maybe the insert()
member function should return some error code instead but runtime_error
seems a bit more convenient since it can (should I think)
contain a description of the error. Please advise.

insert() could return a status object that contains the error message if
things go wrong.

john
 
E

Eric Lilja

Victor Bazarov said:
There was a discussion here recently "Arguments *Against* Exception Use".
Check it out. There was the note by Herb Sutter reminding us that one
shouldn't confuse normal functionality (and processing thereof) with
exceptional situations. If your hash table is _allowed_ to indicate that
insertion didn't happen and that's normal, then it has to be a return code
and not an exception. Something like that, anyway.

V

Thanks for the reply. Say I change the hash table to return an error code
instead of
throwing an exception when the user is trying to insert a value that is
already present
in the hash table (a situation that strikes me as a bit too common to be
called exceptional),
what sort of a mechanism should I implement alongside it if the user wants a
more detailed
error description (could be useful for debugging purposes)?

I haven't checked out the thread you mentioned yet, but I will.

/ Eric
 
E

Eric Lilja

John Harrison said:
Well you can certainly simplify the code, no flag is needed

try
{
hash_table.insert(some_value);
std::cout << some_value << " successfully inserted." << std::endl;
}
catch(const std::runtime_error& e)
{
std::cerr << e.what() << std::endl;
}

Wow, thanks John! After all this time spent learning C++ I never realised
that I could put
it in the same block after the call to the function-that-may-throw. Why
didn't I think of that?
Anyway, this new knowledge will clean up A LOT of my old programs > 100
lines!! Thanks!
insert() could return a status object that contains the error message if
things go wrong.

Yeah, I'm thinking of changing the hash table class to do just that when the
user
is trying to perform an illegal insertion, which doesn't seem very
exceptional to
me. But as I said in my reply to Victor, I still would like the ability to
get a more
detailed error description, but how should I get that with numerical error
codes?
Some variant of errno but built-in in the class?

/ Eric
 
V

Victor Bazarov

Eric said:
[...] Say I change the hash table to return an error code
instead of
throwing an exception when the user is trying to insert a value that is
already present
in the hash table (a situation that strikes me as a bit too common to be
called exceptional),
what sort of a mechanism should I implement alongside it if the user wants a
more detailed
error description (could be useful for debugging purposes)?

John has suggested it, and it seems like a decent solution, to return
a reference to a static object of the class... Of course, you could
easily marry the two concepts. It could be a pseudo-enumerator with
the value/comments and a real object:

template<class T>
class inserter { // your hash table or anything, essentially
class iterator {
...
virtual const std::string& what() const {
return inserter::everythingOK;
}
};

static std::string everythingOK;
static std::string insertionFailed;
static std::string otherError;

class insertionFailed_iterator : public iterator {
const std::string& what() const {
return inserter::insertionFailed;
}
};

class otherError_iterator : public iterator {
...
};

iterator insert(T t);
};
...
inserter<blah> mytable;

inserter::iterator it = mytable.insert(blah());
if (it == inserter::insertionFailed_iterator) {
// insertion failed
}
else {
// use 'it' here
}


Victor
 
E

E. Robert Tisdale

Eric said:
I'm working with a hash table that is encapsulated in a class.
One of its member functions insert() throws an exception
if the insertion fails
(for example, if the value was already present in the hash table).
Now I have client code that looks like this:

bool exception_thrown = false;

try {
hash_table.insert(some_value);

This is a bad example.
The exception handling mechanism isn't necessary
unless the try block evaluates non-trivial expressions
with one or more operators that may throw exceptions.
}
catch(const std::runtime_error& e) {

std::cerr << e.what() << std::endl;

exception_thrown = true;
}

if (!exception_thrown) {

std::cout << some_value << " successfully inserted." << std::endl;
// For debugging purposes, it would be nice to see position here.
}

Using the flag variable exception_thrown strikes me as a bit ugly...
how should I deal with this? If I'm calling a function that
may throw an exception I want to catch that exception.

I can change the hash table class itself if I need to.
Maybe the insert() member function should return some error code instead
but runtime_error seems a bit more convenient
since it can (should I think) contain a description of the error.
Please advise.

I think that you need to redesign your hash table class.
Your insert(const SomeType&) method should return a value
so that it can be used in expressions.
It could return a reference to the has table object
or it could return an exception object.
Whether you decide to throw an exception of return an exception,
the exception object must contain enough information
about the exception to allow the calling program
to handle the exception and recover.
In this case, the exception object may contain a simple error code
or even a boolean value which simply indicates whether or not
the insertion failed. For example:

bool HashTable::insert(const SomeType&) {
// Return true if successful.
}

. . .

if (hash_table.insert(some_value)) {
std::cout << some_value << "successfully inserted."
<< std::endl;
}
 
A

Andre Kostur

Yeah, I'm thinking of changing the hash table class to do just that
when the user
is trying to perform an illegal insertion, which doesn't seem very
exceptional to
me. But as I said in my reply to Victor, I still would like the
ability to get a more
detailed error description, but how should I get that with numerical
error codes?
Some variant of errno but built-in in the class?

Assuming that insert returns an error code on failure (and 0 on success),
what "more detailed error description" could you want more than EEXIST?
(Not sure if errno.h is Standard or not.. might be POSIX).

If insert were only returning a bool, maybe... but only if there were
multiple reasons as to why the insert could fail....
 
M

Markus Elfring

what sort of a mechanism should I implement alongside it if the user wants a
more detailed
error description (could be useful for debugging purposes)?

Please consider that exceptions can not be ignored by the programmer
without additional instructions.
Would you like to guarantee that library users must react to a thrown
"notification"?

Regards,
Markus
 
M

Markus Elfring

But as I said in my reply to Victor, I still would like the ability to
get a more
detailed error description, but how should I get that with numerical error
codes?
Some variant of errno but built-in in the class?

Does the discussion "conversion: errno => exception" offer interesting
and useful informations for you?
http://groups.google.de/[email protected]

Regards,
Markus
 
M

Markus Elfring

bool HashTable::insert(const SomeType&) {
// Return true if successful.
}

How easy is it to forget to check the return code?

Have you got resource limitations or constraints like in EC++ to
exclude the usage of exceptions?
 
M

Michiel Salters

How easy is it to forget to check the return code?

Easy. However, there are situations in which it is reasonable
to use a bool return value to indicate duplicates. You definitely
need to keep that condition separate from std::bad_alloc.
Ignoring duplicates may be a sane strategy.

Regards,
Michiel Salters
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top