Reputation: 175
I'm maintaining rather old legacy code. My forerunners pioneerd in exception handling (<2000). The throw and catch logic to handle non-standard behaviour seems to have worked.
They implemented a nice way to throw:
TL_THROW_EXCEPTION(ISQL_MSG_XML_PARSER_ERROR) << msg;
The TL_THROW_EXCEPTION expands to:
TLThrowTec::CTLThrowExceptionTechnical::ThrowT(__FILE__,__LINE__,
ISQL_MSG_XML_PARSER_ERROR) << msg;
It creates a TLThrowTec::CTLThrowExceptionTechnical instance on the stack, with shift operations to setup a message string. The destructor creates and throws an exception.
A 2008 entry in stackoverflow explains the state of that year: throwing exceptions out of a destructor it seems to have worked then.
But now Visual Studio 17 allows to throw, but not to catch anymore.
As the legacy code is part of an overall system it generates log file entries like "unhandled os exception".
I want to get the catch logic back without to much changes in the source. Best would be to come with a #define for TL_THROW_EXCEPTION.
Is there a way to redefine the macro so that the exception is thrown with the message?
If I search for TL_THROW_EXCEPTION this is last line:
Matching lines: 770 Matching files: 217 Total files searched: 3159
I don't like touching all of them.
Upvotes: 0
Views: 246
Reputation: 27577
Is there a way to redefine the macro?
Yes, simply undefine it and then redefine, something like:
#undef TL_THROW_EXCEPTION
#define TL_THROW_EXCEPTION ...
Of course, if you can think of a way to make it a class
or a function, you're better off doing that after you #undef
it than using a macro.
So more like:
#undef TL_THROW_EXCEPTION
class TL_THROW_EXCEPTION
{ ... }
then define the constructor to create an instance that gives you the desired behavior.
Upvotes: 0
Reputation: 45664
Simply fix that class:
std::uncaught_exceptions()
(plural, not singular) in the ctor.noexcept(false)
to enable propagating exceptions.std::uncaught_exceptions()
Returns the saved count. Otherwise, trying to build the exception caused an exception, and throwing your own into the mess will get std::terminate
called.I hope your constructor uses a std::stringstream
. Otherwise, consider fixing that oversight too.
Upvotes: 0
Reputation: 170084
Modern C++ designates all destructors as non-throwing by default. And if an exception is thrown from any function that is designated non-throwing, the program is terminated immediately. This is because throwing out of destructors is frowned upon. Destructors are called automatically during stack unwinding, while an exception is already in transit. Throwing again will itself terminate the program in such a situation. And all standard containers warn of UB if a destructor of a contained object ever throws.
But your use case is not prone to trigger any of that. ThrowT
objects seem to me as meant to be created as temporaries that immediately throw something, they don't linger around to have their destructor called during stack unwinding of something else. We can therefore mark them as throwing again to restore the functionality. Something like this...
ThrowT::~ThrowT() noexcept(false) {
// as before
}
... will do to make the macro working again.
Upvotes: 1
Reputation: 63124
Just adapt the exception-making type to be the exception, and use:
#undef TL_THROW_EXCEPTION
#define TL_THROW_EXCEPTION(msg_) \
throw YourExceptionType(__FILE__, __LINE__, (msg_))
Since throw
has lower precedence than <<
, this will first evaluate the aggregating expression, then throw its result.
Upvotes: 0