Cy Edmunds said:
Tom Groszko said:
Given a try catch scenario
try
{ dosomething();
}
catch (...)
{ report some error
}
Is there any way to figure out what exception is being thrown and
represented by the ellipsis in the above code?
I am using MS C++ if that environment has something different.
I am catching an error and sure would like to know what is wrong. I have
tried to catch everything in the docs for the library and none of those are
the error.
Thanks
Tom G.
[snip]
You could try this:
try
{
dosomething();
}
catch (std::exception &e)
{
std::cerr << "std::exception " << typeid(e).name() << '\n';
std::cerr << e.what() << '\n';
}
catch (...)
{
std::cerr << "non-standard exception\n";
That is a "non 'standard-exception'" i.e. the standard does not require or
even particularly encourage derivation from std::exception in user code.
Many well respected C++ authors seem to think that the std::exception
hierarchy if not std::exception itself are not teh greatest way to do
exceptions.
}
If you don't know where the error is coming from but whoever threw it was
nice enough to base his exception class on std::exception you should be able
to get some information possibly including the actual type name and perhaps
an error message. OK, so that would be lucky. But if you were getting an
exception from MY code it would work.
catch(...) should be a last resort because once you are there you never know
what to do.
This is not quite true - typically you should release resources allocated in
the try block and throw an exception of a type defined
by your method since your method has failed even if you don't know why. In
general you might not know how to recover but you do know how to clean up
and throw an exception.
You also know that it is a fault in your implementation not the calling
code.
It is a bit tedious but it is strictly speaking incorrect modelling to allow
ANY exception to propagate through your code unless you know its detailed
type because a caller does not know what to expect.
In an ideal world you would put a try block around anything that could throw
and convert all exceptions to a documented set defined for your method.
In a less than ideal world I would suggest that you do this whenever you
have declared some exceptions to throw or you use something that the client
does not know about (e.g. hidden use of networking producing network
exceptions is bad). For other cases you probably shouldn't use try blocks at
all - just use destructors to clean up.
P.S. When initially prototyping or where there are a small number of
possible exceptions I sometimes use the following cheap and cheerful
approach:
struct X
{
static const char E_BADSTUFF1[]; // a suitable string
static const char E_BADSTUFF2[];
void foo()
{
throw E_BADSTUFF1; // a bit lazy
}
void foo2()
{
throw "bad stuff 3"; // very lazy
}
};
This allows printing something useful and equality comparisons:
try
{
x.foo();
}
catch( const char* s )
{
cerr << "ERR: " << s << endl;
if( s == X::E_BADSTUFF1 )
...
}