Paul Floyd
Paul Floyd

Reputation: 6936

Catch exception when class definition is not visible

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

Answers (1)

Christophe
Christophe

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;
}

Online demo

Upvotes: 1

Related Questions