0

Why doesn't this piece of code run without error? Isn't bad_exception supposed to be called automatically when an unexpected exception is encountered? Or is it necessary to set a handler for it?

#include <iostream>
#include <exception>
using namespace std;
class C{};
void test() throw(bad_exception)
{
    throw C();
}
int main()
{
    try
    {
         test();
    } catch(bad_exception& e)
    {
        cout << "Caught ";
    }
}
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
sajas
  • 1,599
  • 1
  • 17
  • 39

4 Answers4

3

In C++03 theory: If you throw an exception that is not in the exception specification, unexpected() gets called. If you have not set the unexpected handler via set_unexpected() this means terminate() gets called which is the case you observed. If you have set an unexpected handler that does not call terminate but throws an exception, and if that exception is not listed in your exception specification, it gets translated into bad_exception. So in order to get the expected result, call set_unexpected() first with an appropriate handler.

In C++03 practice: Some compilers do not support exception specifications at all (other than throw()), others just don't evaluate/check them for correctness. As Herb Sutter points out, exception specifications create a clumsy "shadow type system" that is not easy to handle right (if it is possible at all). Therefore..

... in C++11: Exception specifications are deprecated. You should rather not use them. However, there is a nothrow operator that has a slightly different functionality than throw()


PS: so why have std::bad_exception in C++03? You hav three different regions of code:

  • The function you are writing an exception specification for.
  • The "foreign" code you are calling from that function that might or might not throw an exception that does not match you specification.
  • The (maybe also unknown) unexpected handler that can be anything and should either terminate/exit/abort the program or throw anything.

So if the "foreign" code throws an exception that violates your exception specification, you have three possible outcomes of that:

  1. The handler terminates the program. There is not much you can do about that unless you set your own handler in the function.
  2. The handler throws an exception that matches your exception specification. And all is well.
  3. The handler throws something else. What do you want the runtime to do now? That's where bad_exception comes in: If it is in your specification, the "something else" gets translated into a bad_exception, and the program continues. If it's not, terminate gets called.

Setting your own handler inside the function disables any handler that was previously set by anyone else who just wants to use your function. He will not expect you to disable his handler. Besides, the handler is meant as a global what-happens-if policy and thus is nothing you should care about in a single function implementation.

Arne Mertz
  • 24,171
  • 3
  • 51
  • 90
  • So why do we need bad_exception.. We could have set a handler for unexpected exception which in turn throws something that we can catch? – sajas Nov 27 '12 at 10:50
  • `noexcept` is not the same as `throw()`. – Pete Becker Nov 27 '12 at 12:17
  • thx for the comments - added an answer to the "why bad_exception" question and fixed the noexcept/throw() issue. Thanks for pointing that out. – Arne Mertz Nov 27 '12 at 12:49
2

This should call std::unexpected which by default call std::terminate() as the thrown exception isn't part of the exception specification.

(It does here with g++ on Linux, SunOracle CC on Solaris, IBM xlC on AIX BTW)

If you install an unexpected handler, it works as you expect here:

include <iostream>
#include <exception>
using namespace std;
class C{};

void myunexpected()
{
    throw std::bad_exception();
}

void test() throw(std::bad_exception)
{
    throw C();
}
int main()
{
    try
    {
        set_unexpected(myunexpected);
        test();
    } catch(std::bad_exception& e)
    {
        std::cout << "Caught ";
    }
}
AProgrammer
  • 51,233
  • 8
  • 91
  • 143
  • This should actually call `std::unexpected`, as explain [here](http://stackoverflow.com/a/1410255/160206), which by default calls `std::terminate`. – Björn Pollex Nov 27 '12 at 09:20
  • @BjörnPollex, yes, I was imprecise. I've completed with an example of installing an unexpected handler. – AProgrammer Nov 27 '12 at 09:25
  • So why do we need bad_exception.. We could have set a handler for unexpected exception which in turn throws something that we can catch? – sajas Nov 27 '12 at 10:56
1

As per [except.unexpected], when a function throws an exception not listed in its dynamic exception specification, std::unexpected() is called. According to [unexpected.handler], the default implementation of std::unexpected() simply calls std::terminate().

However, the program can install its own handler, which can (re-)throw an exception. If the exception thus thrown is not allowed by the dynamic exception specification, it can be replaced by std::bad_exception when that is allowed.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
0

Your catch-block would only catch exceptions of the type bad_exception, or a subtype thereof. C does not meet this criterion.

Actually, this question is very similar to yours. The accepted answer explains that if your function throws an exception that does not match the specification (if there is any), then std::unexpected is called, which by default calls std::terminate.

Community
  • 1
  • 1
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283