views:

102

answers:

2

Hello everyone,

I'm working on old code that relies heavily on the exception specifications behavior described in the language standard. Namely, calls to std::unexpected() on exception specification violations of the form described below.

foo() throw(T) { /*...*/ }

Nothrow specifications are indeed guaranteed to not throw, but throw(T) ones are expected to be violated both by design and... well, because the standard expects as much and provides a mechanism to handle it.

The reasons for this are tied to the designers decision of using EH also as an error handling mechanism (controlled by its own error class hierarchy) in addition to exception handling. The idiom presented in EH closely mapped to their needs and they took the path of least effort. This is at least how I see it and isn't particularly shocking to me, given the size and complexity of the system.

I'm however now tasked to include new and unrelated functionality and the code isn't behaving as expected under VC++ 9.0, due to the deviation from the standards regarding exception specifications introduced in 8.0. (reference: Microsoft)

I'm trying to find a way to force the standard behavior. Was hoping for a fallback to be offered by the compiler. But there is none.

Am I out of luck and need to change correctly written standard-obedient code running on the 350,000 lines of code with a fully developed error handling class hierarchy? Or can you think of a way that will help me to force std::unexpected() behavior?

EDIT: I'm providing some background information. The system in question is a School Year Calendars Generator for a school serving a little over 4,000 students distributed among, I'm unsure as to some of the numbers yet, 6 grades and ~190 classes, plus 12 virtual (long-distance teaching) classes. MINGW is out of the question as is any compiler other than VC++ 8.0 or 9.0. This is due to regulations pertaining to software serving the Educational System in this country.

The changes needed to the code are exactly to accommodate the introduction of the virtual classes with a vastly different schema for calendar generation. And then I bumped into this problem. The software makes heavy use of the exceptions mechanism on a few parts of the calendar generation process as a means to control workflow through both unexpected() mappings (saved and restored) and bad_exception mappings, none of which work under VC++. On a purely personal note, I find the mechanism in place actually very elegant even if entirely uncommon. But I digress.

+3  A: 

I don't believe that Visual C++ exception specification behaviour has ever been (or claimed to have been) standards conforming - even before 8.0 - so I'm not sure how the application has been working.

Is it feasible to perform changes such as:

void f() throw(T)
{
    // ...
}

to:

void f()
{
    try
    {
        // ...
    }
    catch (T)
    {
        throw;
    }
    catch (...)
    {
        app_unexpected();
    }
}
Charles Bailey
The last development cycle on this application was built with MinGW (and your assertion now explains to me why. I was under the impression VC++ 8 introduced this change) and produced its last revision on October 2002. Currently MinGW is no longer a possibility due to changes in regulations concerning software for the Education system in my country (I'll in an instant make an edit to my question giving some background information for a better understanding of the situation).
Krugar
I had pondered your solution before. But I'm producing those type of changes only if I cannot negotiate an extension of the current deadline (which is 2 weeks). I don't want to provide that type of legacy to anyone having to use this code in the future. My aim is to either find some undocumented feature that allowed me to fallback to a standards-compliant behavior or completely wipe out the current mechanism.
Krugar
And of course, using boost.pp this can be automated, leaving you with only `void f() try { /* ... */ } THROW(bad_alloc, logical_error)`
Johannes Schaub - litb
+1  A: 

As you mentioned, Visual Studio has an "interesting" way of dealing with exception specifications:

  • throw() has its normal meaning (the function must not throw)
  • anything else (including no exception specification) is interpreted as throw(...)

There is no way to circumvent this. However, the C++ community pretty much agrees that exception specifications are useless. Do you really need runtime checking of error types thrown? Perhaps proper unit testing can replace your runtime checks.

rlbond
+1 for the unit testing. Thanks.The alternative is indeed to completely replace the existing mechanism. To answer your question directly, there is a need for runtime error checking, but this doesn't necessarily need to be supplied through EH as you certainly know. However the change will involve too many of an hour just understanding the current mechanism in its entirety. Then there's the work involved in changing it. And I'm working solo.
Krugar
I'm closing this down and accepting this answer. It makes a specific mention to not being able to turn unexpected() suppression off. As for how to deal with this, I'm fully aware of the possibilities. Thank you both, a lot :)
Krugar