9

Is it possible to handle exceptions in these scenarios:

  1. thrown from constructor before entering main()
  2. thrown from destructor after leaving main()
shiouming
  • 1,889
  • 4
  • 17
  • 26
  • So base on all the suggestions, is it safe to conclude that: (1) Even with try-catch block around constructor/destructor, the exception will still be rethrown. (2) If this happens outside main() scope, i.e. initialization of global object, or auto de-initialization of normal object during termination, exception can't be caught. – shiouming Jan 08 '10 at 09:30
  • Not quite. Ctors can *only* indicate failure through exceptions, since you cannot have a ctor end without constructing an object; so catching exceptions thrown by a ctor must not violate that. You *must* catch any potential exception from a dtor, because dtors are called as part of stack unwinding (which happens when exceptions are thrown). If you do not, then you have *two* exceptions active at the same time, which gets you std::terminate(). –  Jan 08 '10 at 09:58
  • Am reading up this topic from Stroustrup's title. From his explanation, everything sounds like painful design subject to me. – shiouming Jan 08 '10 at 12:10

4 Answers4

23
  1. You can wrap up your constructor withing a try-catch inside of it.
  2. No, you should never allow exception throwing in a destructor.

The funny less-known feature of how to embed try-catch in a constructor:

object::object( int param )
try
  : optional( initialization )
{
   // ...
}
catch(...)
{
   // ...
}

Yes, this is valid C++. The added benefit here is the fact that the try will catch exceptions thrown by the constructors of the data members of the class, even if they're not mentioned in the ctor initializer or there is no ctor initializer:

struct Throws {
  int answer;
  Throws() : answer(((throw std::runtime_error("whoosh!")), 42)) {}
};

struct Contains {
  Throws baseball;
  Contains() try {} catch (std::exception& e) { std::cerr << e.what() << '\n'; }
};
Kornel Kisielewicz
  • 55,802
  • 15
  • 111
  • 149
  • I was surprised when I've learned it too :). It's one of those less known features... – Kornel Kisielewicz Jan 08 '10 at 08:37
  • Ah, forgot about optional initializators passing. Now it's fully esoteric. – Kornel Kisielewicz Jan 08 '10 at 08:49
  • 1
    Function try-blocks also work for almost any function, including main (where you should practically always have one). –  Jan 08 '10 at 09:01
  • But only in constructors they have the real benefit of wrapping the initialization of objects. – Kornel Kisielewicz Jan 08 '10 at 09:12
  • 2
    Note that the exception will always be rethrown at end of the constructor (to prevent there being an object with uninitialised members). – James Hopkin Jan 08 '10 at 09:18
  • You did not use that "less known feature" in the sample. I tried the sample in VC2008, but the exception propagated to the main. – Jagannath Jan 08 '10 at 09:52
  • Jagannath: As James pointed out, you cannot silence exceptions from data members' ctors, you *must* propagate them. The output will still be written to stderr, to show that it was caught, however. –  Jan 08 '10 at 09:56
  • Point 2 could use a tweak: "No, you should never allow exceptions to escape from a destructor." A function, called from a dtor, which throws is fine, the dtor just must make sure to handle it. –  Jan 08 '10 at 10:05
  • I wonder if a call to exit() would also be OK in the constructor-level try block? In any case, there doesn't seem to be any way to recover, since there is no place to continue from as the program hasn't even started to run. But one probably doesn't want to recover from fatal errors in global construction anyway... – UncleBens Jan 08 '10 at 15:38
4

Yes: don't use dangerous global objects!

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • 1
    This is the best answer (after you add "or dangerous singletons"), but I'm out of votes for the next 14 hours! –  Jan 08 '10 at 09:04
  • +1: in name of Roger -- however, I'd like to point out that there are situations that this is impossible, especially if using some wierd API that makes the decision for you. – Kornel Kisielewicz Jan 08 '10 at 09:14
0

It might be possible to set an exception handler before construction / destruction of the objects in question, that one should be able to handle those exceptions.

For constructors, there's some weird new syntax that allows exceptions to be caught within the constructor. Not sure how that works, and it's not commonly implemented in many compilers.

For destructors, you have to wrap the content of the destructor in a try { code(); } catch(...) {} block. Which may not always be the desired behavior, depending on what you want to achieve in that destructor.

tobing
  • 19
  • 2
  • "New" as in over 15 years old? :P It *is* commonly implemented and is part of the C++ standard. –  Jan 08 '10 at 09:03
0

Short answer: no.

Any global object that throws an exception in its constructor will cause an unhandled exception (that is, terminate be called).

Any class that throws an exception in its destructor is a broken class.

Using the singleton pattern rather than globals will give you more options.

James Hopkin
  • 13,797
  • 1
  • 42
  • 71
  • I find the opposite: singletons reduce options. Putting application-level objects as local variables in main works beautifully though. –  Jan 08 '10 at 10:08
  • @Roger I don't think we disagree - I only said singletons give you more options than globals. – James Hopkin Jan 08 '10 at 11:19
  • No, I think singletons reduce options compared to global objects, as at least with globals you can put them all in one TU to control initialization order, and other such things. –  Jan 10 '10 at 10:08
  • 1
    Oh, we do disagree then ;-). Singletons are only created if and when needed, and in the rare case of one singleton depending on another, that works automatically, rather than the object instances having to be carefully ordered. Singletons can also be kept private to a particular area of code, rather than needing to be dumped in main.cpp. And wrt to the original question, a variation on the singleton pattern would allow you to handle a singleton not constructing properly (perhaps grey out the UI and display an error, rather than crashing). – James Hopkin Jan 11 '10 at 17:06