Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Chained Exceptions

Status
Not open for further replies.

maluk

Programmer
Oct 12, 2002
79
SG
The Exception class maintains a pointer to an Exception class. This pointer is the cause of the Exception that was thrown. However, if there is no cause, that pointer will point to nothing and upon usage will cause a catastrophe (using a pointer that points to nothing) as with the case below:

Code:
...

    try
    {
        throw Exception("Ex") ;
    }
    catch(Exception& e)
    {
        std::cout << e.what() << std::endl ;     // OK
        std::cout << e.cause().what() << std::endl ;     // points to
nothing: CATASTROPHE!
    }

Apart from the problem stated above, there is also an issue of the deletion of the pointer to an Exception member.

I believe that my code has memory leaks and holes in them. Could someone please give suggestions for improvement?Exception class is shown below.

[ Exception.hpp ]
Code:
#ifndef MX_EXCEPTION_H
#define MX_EXCEPTION_H

#include <exception>
#include <string>


 class Exception
 {
 public:
  // Constructs a new exception with null message.
  Exception(void) ;
  // Destructor
  virtual ~Exception(void) ;
  // Constructs a new exception with the specified message.
  Exception(const string& message) ;
  // Constructs a new exception with the specified message and cause.
  Exception(const string& message, const Exception& cause) ;

  // Initializes the cause of this exception.
  void initCause(const Exception& cause) ;

  // Returns the message of this exception.
  const char* what(void) const ;
  // Returns the cause of this exception
  const Exception& cause(void) const ;
 private:
  string what_ ;
  Exception* cause_ ;
 } ;
#endif // MX_EXCEPTION_H

[ Exception.cpp ]
Code:
#include "Exception.hpp"

 // Constructs a new exception with null message.
 Exception::Exception(void)
 {
 }

 // Destructor
 Exception::~Exception(void)
 {
 }

 // Constructs a new exception with the specified message.
 Exception::Exception(const string& message) : what_(message)
 {
 }

 // Constructs a new exception with the specified message and cause.
 Exception::Exception(const string& message, const Exception& cause) :
what_(message), cause_(new Exception(cause))
 {
 }

 // Initializes the cause of this exception.
 void Exception::initCause(const Exception& cause)
 {
  this->cause_ = new Exception(cause) ;
 }

 // Returns the message of this exception.
 const char* Exception::what(void) const
 {
  return( what_.c_str() ) ;
 }

 // Returns the cause of this exception
 const Exception& Exception::cause(void) const
 {
  return ( *cause_ ) ;
 }


Rome did not create a great empire by having meetings, they did it by
killing all those who opposed them.

- janvier -
 
To solve the "no cause" problem, just check to see if a cause exists before trying to call what() on it.

You do have memory leaks. You never delete the stuff you allocate with new.
 
chipperMDW,

What would you suggest to remove the memory leak? Who should handle resource deallocation for the cause_?

Rome did not create a great empire by having meetings, they did it by
killing all those who opposed them.

- janvier -
 
You should not return a reference to your exception if it might be null (which it might be). Return a pointer and check that pointer for null before you use it.

Maybe a better design idea would be to have your what() function check to see if it has a cause and then append that exception's what() data to the returned value. This way you could have as many nested exceptions as you want, and your catch() handler will only need to call what() on the one it caught. If necessary you could add a bool (optionally optional) that tells the code whether to append the nested exception's message. That way you could get either the full message or just the specific message.

That design change would allow you to get rid of the cause() function altogether (which is a good thing - encapsulation).

As far as your memory leak, you do have one. In the two constructors that don't initialize cause_, add "cause_(0)" to the initialization list. Then, in your destructor, "delete cause_;". If cause_ is 0 (or null) then the delete will do nothing, otherwise it will delete the exception you created with new.
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Sponsor

Back
Top