So, I am try to write a simple base Exception class for C++, based on the Java Exception class. I'm sure there are great libraries out there already, but I am doing this for practice, not production code, and I'm curious and always looking to learn. One of the things the Java's Exception does, which I would like to also implement, is the concept of a 'cause'. In Java, a new Exception with a cause looks like:
Exception cause = new Exception();
Exception newExcept = new Exception(cause);
However, in C++, passing an Exception as an argument to the constructor is how the copy constructor is called. So, there's the conceptual disconnect between copying the Exception and creating a new Exception with a cause. This isn't a problem in Java, obviously.
I guess I'm just wondering what the best way to handle this would be. A few ideas I had were:
- Differentiate with a dummy variable
- Just create new Exception, and called setCause() method
- Something like copy constructor is
Exception(Exception &)
and constructor with cause is开发者_高级运维Exception(Exception *)
Thanks
The exception - when allocated on the stack (I would strongly recomend this) - is freed after the catch clause. So you need to create a copy of the "inner" exception in the newly created exception. If you catch a base class of your exception it will loose it's correct type unless you give your exception a clone method.
#include <string>
#include <exception>
class MyBaseException : public std::exception
{
public:
MyBaseException(const std::string& what = std::string("MyBaseException"))
: m_BaseException(0), m_What(what) {} //Constructor without inner exception
MyBaseException(const MyBaseException& innerException, const std::string& what = std::string("MyBaseException"))
: m_BaseException(innerException.clone()), m_What(what) {} //Constructor with inner exception
template <class T> // valid for all subclasses of std::exception
MyBaseException(const T& innerException, const std::string& what = std::string("MyBaseException"))
: m_BaseException(new T(innerException)), m_What(what) {}
virtual ~MyBaseException() throw()
{ if(m_BaseException) { delete m_BaseException; } } //don't forget to free the copy of the inner exception
const std::exception* base_exception() { return m_BaseException; }
virtual const char* what() const throw()
{ return m_What.c_str(); } //add formated output for your inner exception here
private:
const std::exception* m_BaseException;
const std::string m_What;
virtual const std::exception* clone() const
{ return new MyBaseException(); } // do what ever is necesary to copy yourselve
};
int main(int argc, char *argv[])
{
try {
try {
throw std::exception();
}
catch(const std::exception& e) {
throw MyBaseException(e, "bad");
}
}
catch (const MyBaseException& e) {
throw MyBaseException(e, "even worse");
}
//throw MyBaseException(1, "will not compile");
}
You could use the factory model:
Exception cause = Exception.Create();
Exception newExcept = Exception.Create( Exception cause );
Just add the string of the cause exception to the current exception:
try
{
throw std::runtime_error("Failed to work");
}
catch(std::exception const& e)
{
// New exception (add origianl exception text).
throw std::runtime_error(std::string("We were doing poobar when: ") + e.what());
}
You're question is unclear, and doesn't even seem to be Java properly but a Java idiom which is supported by a library. I am guessing the idiom you describe is passing the original exception as an argument to an exception you create when rethrowing.
The solution is to create a library_exception ( or whatever you want to call it )
class library_exception: public std::exception
{
...
public:
library_exception(const std::exception &e)
...
}
...
catch(const std::exception &e)
{
...
throw library_exception(e);
}
Different classes no copy constructor called.
精彩评论