Reputation: 6936
I'm working on an issue whereby a corrupt input file is causing an exception to be thrown. The exception class is defined in an implementation file and thus not visible to me. It does inherit from std::exception
.
I tried simply forward declaring the exception class, since I'm just catching it by reference. However, this gave me a error: invalid use of incomplete type
compiler error (using GCC 6.2 on Linux). I suppose that the compiler needs the full exception object type so that it can rethrow the exception if needed.
So this is what I'd like to do:
// library.cpp
namespace FOO {
struct SomeException : public std::exception
{
// string member, virtual dtor, ctor taking one arg and virtual what()
};
void doStuff() {
}
}
// my main.cpp
namespace FOO
{
struct SomeException;
}
int main()
{
try
{
FOO::doStuff();
}
catch (FOO::SomeException& e)
{
// ignore e, but I know where it came from so log
// an appropriate message
}
catch (std::exception& e)
{
// most other exceptions, log `what()` message
}
catch(...)
{
// tell user to contact customer support
}
}
Just printing the what()
message isn't appropriate to my context.
I could ask the other team to move their exception class definition into a header. That will probably be a slow process. I suppose I could also do a string comparison on the what()
message, but that seems ugly.
Are there any other options?
(BTW I can't see any mention of this via Google, but this does seem to be a sort of anti-pattern, the "throw-only exception").
Upvotes: 3
Views: 367
Reputation: 73520
If you don't have access to the original class, you won't be able to catch it correctly:
C++ standard / [except.handle]:
The exception-declaration in a handler describes the type(s) of exceptions that can cause that handler to be entered. The exception-declaration shall not denote an incomplete type, an abstract class type, or an rvalue reference type. The exception-declaration shall not denote a pointer or reference to an incomplete type, other than [cv void*].
So there's no ideal and clean solution. But maybe an acceptable work-around: a class derived from std::exception is polymorphic. So you could consider using typeid()
(eventually in conjunction with type_index
) to identify the real type in the catch (std::exception& e)
block.
IMHO, it should be an acceptable way to differentiate between unknown exceptions when .what()
is not an alternative. The inconvenience is however that the value of type_info
data (eg. typeid(e).name()
) is not defined in the standard, which makes any hard-coded value non portable.
Proof of concept:
//somewhere
class MyExcept : public std::exception { };
...
// somewhere else
try {
throw std::exception();
} catch (std::exception &e) {
std::cout <<"case 1: " << typeid(e).name() << std::endl;
}
try {
throw MyExcept();
} catch (std::exception &e) {
std::cout <<"case 2: "<< typeid(e).name() << std::endl;
}
Upvotes: 1