Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2007-09-13 14:23:01


Hello,

I am requesting comments, both for and against a "sticky exception".
A sticky exception is one in which once thrown, is very hard to catch
and handle, without an implicit rethrow. This represents some
condition which the thrower believes is sufficiently severe that the
application (or thread) should clean up resources, but not be allowed
to continue, even with a catch (...) which does not rethrow.

This can be implemented very simply with a class that owns the right
to rethrow on destruct, and passes that right along within its copy
constructor:

class sticky_exception
{
     bool owns_;
     sticky_exception& operator=(const sticky_exception&);
public:
     sticky_exception() : owns_(true) {}
     sticky_exception(sticky_exception& s) : owns_(s.owns_) {s.owns_ =
false;}
// sticky_exception(sticky_exception&& s) : owns_(s.owns_) {s.owns_
= false;}
     ~sticky_exception() {if (owns_) {sticky_exception s; throw s;}}
};

Please go ahead and experiment with such an exception. I would like
to hear your experiences both good and bad. Here is one test driver:

#include <iostream>

void f3()
{
     try
     {
         sticky_exception s;
         throw s;
     }
     catch (...)
     {
         std::cout << "catch in f3\n";
     }
     std::cout << "f3 return\n";
}

void f2()
{
     try
     {
         f3();
     }
     catch (...)
     {
         std::cout << "catch in f2\n";
     }
     std::cout << "f2 return\n";
}

void f1()
{
     try
     {
         f2();
     }
     catch (...)
     {
         std::cout << "catch in f1\n";
     }
     std::cout << "f1 return\n";
}

int main()
{
     try
     {
         f1();
     }
     catch (...)
     {
         std::cout << "catch in main\n";
     }
     std::cout << "main return\n";
}

which should output:

catch in f3
catch in f2
catch in f1
catch in main

and then terminate abnormally. Note that no function returned
normally (no "return" statements printed).

One possible variation of the above design is to place a reset()
method in the exception which would cure its suicidal tendencies:

class sticky_exception
{
     bool owns_;
     sticky_exception& operator=(const sticky_exception&);
public:
     sticky_exception() : owns_(true) {}
     sticky_exception(sticky_exception& s) : owns_(s.owns_) {s.owns_ =
false;}
// sticky_exception(sticky_exception&& s) : owns_(s.owns_) {s.owns_
= false;}
     ~sticky_exception() {if (owns_) {sticky_exception s; throw s;}}
     void reset() {owns_ = false;}
};

One could then catch it and reset it:

     catch (sticky_exception& e)
     {
         e.reset();
         std::cout << "sticky_exception fully handled\n";
     }

Note that with the above modification, catch (...) would still always
automatically rethrow a sticky_exception. One would need to add the
extra catch(sticky_exception&) shown above to get back the old
behavior of catch (...).

Do you see a use for such a class? Would you use it? Would you want
libraries you're using to use it? Do you have real world example
conditions which fit this use case? Or is it just evil (and why)?

Thanks much,
Howard


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk