Templated throw() specifications.

Discussion in 'C++' started by jason.cipriani@gmail.com, Jun 5, 2008.

  1. Guest

    Consider this program, which defines a template class who's template
    parameter is the type of an exception that can be thrown by members of
    the class:

    === BEGIN EXAMPLE ===

    #include <iostream>
    #include <string>
    using namespace std;

    void function () throw (string) {
    throw string("Oops");
    }

    template <class EX> class A {
    public:
    typedef void (* FN) ();
    explicit A (FN f) : f_(f) { }
    void Call () throw (EX) { f_(); }
    private:
    FN f_;
    };

    int main () {
    A<string> a(&function);
    try {
    a.Call();
    } catch (const string &s) {
    cout << s << endl;
    }
    }

    === END EXAMPLE ===

    The goal of the above is to allow the callback function to throw any
    exception it wants (not necessarily derived from std::exception, so
    simply specifying that is not an option), and still have the generated
    template code for A have the correct throw() specifier for A::Call().

    I have a couple of questions:

    1. Is having a correct exception specifier even necessary? It's always
    been one of those things that C++ has that compilers never seem to
    care about (compare to Java, for example, where it is strictly
    enforced). VC++ actually generates a compiler warning that throw()
    specifiers are ignored, GCC doesn't care, Borland's compiler is the
    only one I know of off the top of my head that actually produces
    diagnostics when throw() specifications are violated. If it really
    doesn't matter (and won't matter in C++0x either), then the above
    template stuff is completely unnecessary since I can just declare
    Call() with no exception specification at all and not have to deal
    with it.

    2. If having the correct specification is necessary, is there some
    trick I can use to keep you from having to explicitly specify the
    exception type template parameter when declaring an A? Some way that I
    can make it implicit? In the above program, for example, function() is
    declared as throwing a string -- is there some way I can make A<> be
    aware of that so I can do "A a(function)" instead of "A<string>
    a(function)"? AFAIK function pointer types can't have throw()
    information in them so putting it in the A::FN type is not something I
    seem to be able to do.

    Hopefully this question makes sense; maybe I am thinking about it too
    much, but I never really feel comfortable when I throw an exception
    from a function that is declared with no exception specifier at all --
    plus it's a useful self-documentation tool as well.

    Thanks,
    Jason
    , Jun 5, 2008
    #1
    1. Advertising

  2. Guest

    On Jun 4, 7:58 pm, ""
    <> wrote:
    > It's always
    > been one of those things that C++ has that compilers never seem to
    > care about (compare to Java, for example, where it is strictly
    > enforced). VC++ actually generates a compiler warning that throw()
    > specifiers are ignored, GCC doesn't care, Borland's compiler is the
    > only one I know of off the top of my head that actually produces
    > diagnostics when throw() specifications are violated.


    Also, Comeau doesn't care about things like this either:

    void function () throw (A) {
    throw NotA();
    }
    , Jun 5, 2008
    #2
    1. Advertising

  3. Kai-Uwe Bux Guest

    wrote:

    > Consider this program, which defines a template class who's template
    > parameter is the type of an exception that can be thrown by members of
    > the class:
    >
    > === BEGIN EXAMPLE ===
    >
    > #include <iostream>
    > #include <string>
    > using namespace std;
    >
    > void function () throw (string) {
    > throw string("Oops");
    > }
    >
    > template <class EX> class A {
    > public:
    > typedef void (* FN) ();
    > explicit A (FN f) : f_(f) { }
    > void Call () throw (EX) { f_(); }
    > private:
    > FN f_;
    > };
    >
    > int main () {
    > A<string> a(&function);
    > try {
    > a.Call();
    > } catch (const string &s) {
    > cout << s << endl;
    > }
    > }
    >
    > === END EXAMPLE ===
    >
    > The goal of the above is to allow the callback function to throw any
    > exception it wants (not necessarily derived from std::exception, so
    > simply specifying that is not an option), and still have the generated
    > template code for A have the correct throw() specifier for A::Call().


    What if the callback function can throw objects of various types?


    > I have a couple of questions:
    >
    > 1. Is having a correct exception specifier even necessary? It's always
    > been one of those things that C++ has that compilers never seem to
    > care about (compare to Java, for example, where it is strictly
    > enforced). VC++ actually generates a compiler warning that throw()
    > specifiers are ignored, GCC doesn't care, Borland's compiler is the
    > only one I know of off the top of my head that actually produces
    > diagnostics when throw() specifications are violated.


    You seem to misunderstand throw specifications. They are enforced at
    run-time not at compile time. If an exception wants to unwind the stack
    past a function from which it is not allowed to escape according to the
    exception specification, then the function unexpected() is called.


    > If it really
    > doesn't matter (and won't matter in C++0x either), then the above
    > template stuff is completely unnecessary since I can just declare
    > Call() with no exception specification at all and not have to deal
    > with it.


    By and large, throw specifications can be considered useless with the
    notable exception of throw().


    [snip]


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Jun 5, 2008
    #3
  4. Guest

    On Jun 4, 8:22 pm, Kai-Uwe Bux <> wrote:
    > You seem to misunderstand throw specifications. They are enforced at
    > run-time not at compile time. If an exception wants to unwind the stack
    > past a function from which it is not allowed to escape according to the
    > exception specification, then the function unexpected() is called.


    I did misunderstand; I am so used to compilers enforcing it in Java
    that I just kind of assumed C++ would handle them similarly.
    Fascinating! I had no idea that you could use set_unexpected() to
    change the behavior. In fact, long ago I had once thrown an exception
    from a function with a different throw() specification, and the
    program terminated. I had immediately assumed that it was because
    perhaps the compiler had performed some optimizations or something and
    some weird internal error occurred when I threw an exception it didn't
    expect to have to handle when compiling the code. I didn't even look
    into it any further, that event just made me paranoid and started me
    down the road of always using throw() specifications and sticking to
    them (which I guess isn't a bad thing but I did it for the wrong
    reasons).

    So, when I test this with GCC 4.1.2:

    class A { };
    class B { };
    void f1 () throw (A) { throw B(); }
    void f2 () { throw B(); }

    A call to f1() leads to unexpected() being called, as expected (heh).
    However, a call to f2() works just fine. It seems that not specifying
    throw(...) at all is the same as saying "this function can throw
    anything it wants". That's correct, right? It's not a GCC quirk?

    Now, in that case, I still have my original question although for
    different reasons. I'd like to be able to enforce strict exception
    handling at run-time, and so I'd need to specify the exception type
    that the "callback function" can throw in that template class. Right?
    Is there a better way to do that? If my goal is to enforce that kind
    of exception handling, and my situation is like what it was in my
    original post (example at end of this post for reference), is that the
    way to do it?

    > > If it really
    > > doesn't matter (and won't matter in C++0x either), then the above
    > > template stuff is completely unnecessary since I can just declare
    > > Call() with no exception specification at all and not have to deal
    > > with it.

    >
    > By and large, throw specifications can be considered useless with the
    > notable exception of throw().


    Do you think that they are reliably useful for checking for developer
    errors at runtime, at least?

    Thanks,
    Jason


    > === BEGIN EXAMPLE ===


    > #include <iostream>
    > #include <string>
    > using namespace std;


    > void function () throw (string) {
    > throw string("Oops");
    > }


    > template <class EX> class A {
    > public:
    > typedef void (* FN) ();
    > explicit A (FN f) : f_(f) { }
    > void Call () throw (EX) { f_(); }
    > private:
    > FN f_;
    > };


    > int main () {
    > A<string> a(&function);
    > try {
    > a.Call();
    > } catch (const string &s) {
    > cout << s << endl;
    > }
    > }


    > === END EXAMPLE ===


    > The goal of the above is to allow the callback function to throw any
    > exception it wants (not necessarily derived from std::exception, so
    > simply specifying that is not an option), and still have the generated
    > template code for A have the correct throw() specifier for A::Call().
    , Jun 5, 2008
    #4
  5. Guest

    On Jun 4, 9:02 pm, ""
    <> wrote:
    > Now, in that case, I still have my original question although for
    > different reasons. I'd like to be able to enforce strict exception
    > handling at run-time, and so I'd need to specify the exception type
    > that the "callback function" can throw in that template class. Right?
    > Is there a better way to do that? If my goal is to enforce that kind
    > of exception handling, and my situation is like what it was in my
    > original post (example at end of this post for reference), is that the
    > way to do it?


    Or, do you think, in that situation, it's better to declare Call()
    with no throw specification at all, letting it throw anything, and
    just let the program abort if whoever is calling Call() doesn't handle
    the exception that the callback function throws?

    That seems like a simpler solution.

    Jason
    , Jun 5, 2008
    #5
  6. Kai-Uwe Bux Guest

    wrote:

    > On Jun 4, 9:02 pm, ""
    > <> wrote:
    >> Now, in that case, I still have my original question although for
    >> different reasons. I'd like to be able to enforce strict exception
    >> handling at run-time, and so I'd need to specify the exception type
    >> that the "callback function" can throw in that template class. Right?
    >> Is there a better way to do that? If my goal is to enforce that kind
    >> of exception handling, and my situation is like what it was in my
    >> original post (example at end of this post for reference), is that the
    >> way to do it?

    >
    > Or, do you think, in that situation, it's better to declare Call()
    > with no throw specification at all, letting it throw anything, and
    > just let the program abort if whoever is calling Call() doesn't handle
    > the exception that the callback function throws?
    >
    > That seems like a simpler solution.


    Yes. It is simpler.

    An exception specification is like an assert(). However, unlike an assert()
    it is usually not locally verifiable especially in templated code or code
    that calls functors because in that client supplied stuff might get
    executed and throw anything the client felt like throwing.

    E.g., look at something simple like

    template < typename InIter, typename OutIter, typename T >
    OutIter transform ( InIter from, InIter to, OutIter where, T t ) {
    while ( from != to ) {
    *where++ = t( *from++ );
    }
    return ( *where );
    }

    Any line in here might throw. Especially t( *from ) can throw anything and
    the assignment operator might try to copy huge data and run out of memory.
    A correct throw specification based upon the types is impossible (since
    what can be thrown might actually depend on the _value_ of t not just on
    the type T).

    It is much better to leave the decision on what can be thrown to the client
    and in turn let it be the clients responsibility to make sure every
    possible exception is handled correctly.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Jun 5, 2008
    #6
  7. Guest

    On Jun 5, 3:33 am, Kai-Uwe Bux <> wrote:
    > > Or, do you think, in that situation, it's better to declare Call()
    > > with no throw specification at all, letting it throw anything, and
    > > just let the program abort if whoever is calling Call() doesn't handle
    > > the exception that the callback function throws?

    >
    > > That seems like a simpler solution.

    >
    > Yes. It is simpler.


    That's the way I ended up doing it, rather than messing around with
    the throw() specifications.

    > An exception specification is like an assert(). However, unlike an assert()
    > it is usually not locally verifiable especially in templated code or code
    > that calls functors because in that client supplied stuff might get
    > executed and throw anything the client felt like throwing.


    This makes complete sense to me, and clears everything up. Thanks.

    > It is much better to leave the decision on what can be thrown to the client
    > and in turn let it be the clients responsibility to make sure every
    > possible exception is handled correctly.


    Thanks a lot for your reply, that answers all my questions.

    Jason
    , Jun 8, 2008
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Kerri
    Replies:
    2
    Views:
    12,999
    Kevin Spencer
    Oct 27, 2003
  2. Replies:
    15
    Views:
    7,493
    Roedy Green
    Sep 8, 2005
  3. RA Scheltema
    Replies:
    3
    Views:
    382
    RA Scheltema
    Jan 6, 2004
  4. Marijn
    Replies:
    5
    Views:
    442
    Marijn
    Feb 13, 2004
  5. Emanuele D'Arrigo

    To throw or to throw not?

    Emanuele D'Arrigo, Nov 14, 2008, in forum: Python
    Replies:
    6
    Views:
    312
    Emanuele D'Arrigo
    Nov 15, 2008
Loading...

Share This Page