Suppose I have two inheritance hierarchies I'm dealing with in C++. One inherits from std::exception
(new hierarchy), and the other inherits from Exception
(legacy C++ Builder VCL base exception class). If I call code that may throw either type of exception, I have to write code like this:
try {
// do stuff....
Function1();
Function2();
} catch (std::exception &ex) {
std::cout << "STL exception caught: " << ex.what() << std::endl;
} catch (Exception &ex) {
std::cout << "Legacy exception caught: " << ex.Message.c_str() << std::endl;
} catch (SomeOtherVendorLibraryException &ex) {
// etc.
}
The problem is that each caller needs to have all these catch clauses to try to get every last type of exception, since C++ has no one true, enforced exception base class you can use as a catch-all (e.g. System.Exception
class in C#). (catch (...)
is a non-starter since you don't have a way of knowing what you caught, and some dangerous system exceptions, like access violations, could be caught as well which are better left untrapped.)
I would like to wrap these "legacy" exceptions into a class in the std::exception
hierarchy. This concept of wrapping 3rd-party exceptions into your own exception system isn't entirely unprecedented. For example, the .NET Framework wraps broad sets of errors in other systems (e.g. COMException
). Ideally, I'd like to see something like this:
class LegacyException : public std::runtime_error {
public:
// construct STL exception from legacy exception
LegacyException(const Exception &ex) : std::runtime_error(ex.Message.c_str()) {}
};
try {
// In reality, this throw will happen in some function we have no control over.
throw Exception("Throwing legacy exception!");
} catch (std::exception &ex) {
// Ideally, the compiler would use the LegacyException constructor
// to cast the thrown Exception to a LegacyException, which ultimately
// inherits from std::exception.
std::cout << ex.what() << std::endl;
}
Understandably, the exception is never caught - it would be asking quite a bit of magic from the compiler for it to catch it.
Is there a solution that might be similar to the above for wrapping a legacy exception, and achieves these goals?
Having worked with BC++Builder I have met the same problem, and macros seemed to be the only solution at the time.
The "cleaner" (hum...) solution is probably a "double-try-catch": the inner try-catch converts your legacy exception into a standard class, and the outer one actually handles the exception.
I don't have the code at hand (it's been years) but basically it boils down to:
#define DTRY try { try
#define DCATCH catch (Exception& e) { throw LegacyException(e); } } catch
DTRY {
...
}
DCATCH(std::exception& e) {
// handle the exception
}
Yes I know it's ugly, but when I worked with Borland I didn't find anything better. Fact is, at that time Borland was awfully non-standard and I have no idea how it evolved since, maybe you can do better nowadays. Hope this helps anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With