Developing Custom Exception Handler :: C++

kuphryn

Senior member
Jan 7, 2001
400
0
0
Hi.

I would like to create a custom class exception handler. I want to use it for arbitrary exceptions that are not part of the exception library.

I am having a problem with such a class. Here is the code for that exception class.

-----
#ifndef CEXCEPTIONHANDLE_H
#define CEXCEPTIONHANDLE_H

class ExceptionHandle
{
public:
ExceptionHandle(const char *error) : eMessage(error) {}
const char *what() const throw()
{
return eMessage;
}

private:
const char *eMessage;
};

#endif
-----

I basic want to *throw* a character string to the exception handle. Afterward, have a catch function to call what().

Here is an example of a try/catch.

----
try
{
function(x);
}

catch (ExceptionHandle *e)
{
cerr << e->what();
}
-----
function(int X)
{
if (X == 0)
throw ExceptionHandle("Error: X equals zero.");
}
-----

The program I am working on works, but it crashes whenever "throw ExceptionHandle("Error: X equals zero.");" occurs.

Does anyone know what is wrong with my design and/or implementation?

Thanks,
Kuphryn
 

singh

Golden Member
Jul 5, 2001
1,449
0
0
This might fix the problem:

Where you have the line "throw ExceptionHandle("Error: X equals zero.");", change to:

throw new ExceptionHandle("Error: X equals zero.");
 

kuphryn

Senior member
Jan 7, 2001
400
0
0
Okay. Thanks.

I believe the problem was due to these pointer related calls:

-----
const char *eMessage
-----

and/or

-----
catch (ExceptionHandle *e)
-----

I will do two things.

1) I will replace "const char *eMessage" with "const string eMessage."
2) I will replace "catch (ExceptionHandle *e)" with "catch (ExceptionHandle &e)."

First, is the problem caused by "*e" pointing to something that no longer exists? How can that be if I am throwing an exception each time?

I can also use your method of adding "new" to "throw...new."

Which ones of these changes should *fix* the problem most elegantly?

Thanks,
Kuphryn

P.S. A member at Gamedev mentioned about deriving exception classes from the *exception* library. How important is that?
 

singh

Golden Member
Jul 5, 2001
1,449
0
0
Here we go:



<< I will replace "const char *eMessage" with "const string eMessage." >>



Makes no difference really, use the one you like.



<< I will replace "catch (ExceptionHandle *e)" with "catch (ExceptionHandle &e)." >>



This will work ('new' keyword not required when throwing the exception).



<< First, is the problem caused by "*e" pointing to something that no longer exists? How can that be if I am throwing an exception each time? >>


Yes. The exception object got created, but was destroyed before it got to the handler, so the catch() handler was not called. I suggest you use the debugger and set breakpoints all over the place. Then just track the execution. You will know exactly what's going on.

You could use: catch (ExeceptionHandle e) and throw ExceptionHandle(...) if you defined a copy constructor.

As for elegance, just you the one you need. With the pointer (*e), you will have to delete the exception once you were done with it. With the reference (&e), it would delete itself. The latter seams more manageable, but it's up to you.



<< A member at Gamedev mentioned about deriving exception classes from the *exception* library. How important is that? >>



Is there a standard exception library in C++? I am not very experienced with exceptions. I've never created any. In my opinion, it doesn't matter. Do it the way you like, after all that is why the exception mechanism exists in the first place.
 

kuphryn

Senior member
Jan 7, 2001
400
0
0
Thanks.

I will catch exceptions via reference from now on. I am used to catching exceptions via value. The exception above is the first time I have tried catching one via pointer.

I am not sure how breakpoints work in Visual C++. I sometime sees the debugger insert a red dot where it found error(s) during a simulation.

Kuphryn
 

singh

Golden Member
Jul 5, 2001
1,449
0
0
Breakpoints are very simple. Select the statement that you want the debugger to stop at, and press F9 (the statement gets marked with a red dot). Repeat for any other breakpoints you wish to set. Once they're set, press F5 and the program starts execution. See the MSDN documentation for further help.
 

singh

Golden Member
Jul 5, 2001
1,449
0
0


<< I will catch exceptions via reference from now on. I am used to catching exceptions via value. The exception above is the first time I have tried catching one via pointer. >>



You can still do that, but you will need to define a copy constructor for your class (that will of course, entail some overhead depending on what you do in there).
 

kuphryn

Senior member
Jan 7, 2001
400
0
0
Thanks.

I made the follow changes.

-----
class ExceptionHandle : public exception
{
public:
ExceptionHandle(const std::string &error) : eMessage(error.c_str()) {}

virtual const char *what() const throw()
{
return eMessage.c_str();
}

private:
const std::string eMessage;
};
-----

...throw ExceptionHandle("...");

catch (ExceptionHandle &error)
{
cerr << error.what();
}

-----

I derived ExceptionHandle from class exception. bac_alloc is derived from exception too. Can I rely on ExceptionHandle to catch bac_alloc too?

For example, let say I use the class above in a try/catch. Is the follow right?

try
{...}

catch (exception::bad_alloc &error)
{
cerr << error.what();
}

Note that I am relying on the fact that ExceptionHandle is a derivative of class exception.

Kuphryn
 

bsobel

Moderator Emeritus<br>Elite Member
Dec 9, 2001
13,346
0
0
Short answer, yes.

Long answer (Google saved me from typing it all out!);

Since exceptions are a run-time and not a compile-time feature, standard C++ specifies the rules for matching exceptions to catch-parameters a little differently than those for finding an overloaded function to match a function call. You can define a handler for an object of type T several different ways. In the examples that follow, the variable t is optional, just as it is for ordinary functions in C++:

catch(T t)
catch(const T t)
catch(T& t)
catch(const T& t)

Such handlers can catch exception objects of type E if:

1. T and E are the same type, or
2. T is an accessible base class of E at the throw point, or
3. T and E are pointer types and there exists a standard pointer conversion from E to T at the throw point. T is an accessible base class of E if there is an inheritance path from E to T with all derivations public.

To understand the third rule, let E be a type pointing to type F, and T be a type that points to type U. Then there exists a standard pointer conversion from E to T if:

1. T is the same type as E, except it may have added any or both of the qualifiers const and volatile, or
2. T is void*, or
3. U is an unambiguous, accessible base class of F. U is an unambiguous base class of F if F's members can refer to members of U without ambiguity (this is usually only a concern with multiple inheritance).

The bottom line of all these rules is that exceptions and catch parameters must either match exactly, or the exception caught by pointer or reference must be derived from the type of the catch parameter.

Bill