Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Templated throw() specifications.

Reply
Thread Tools

Templated throw() specifications.

 
 
jason.cipriani@gmail.com
Guest
Posts: n/a
 
      06-04-2008
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
 
Reply With Quote
 
 
 
 
jason.cipriani@gmail.com
Guest
Posts: n/a
 
      06-05-2008
On Jun 4, 7:58 pm, "(E-Mail Removed)"
<(E-Mail Removed)> 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();
}

 
Reply With Quote
 
 
 
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      06-05-2008
http://www.velocityreviews.com/forums/(E-Mail Removed) 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
 
Reply With Quote
 
jason.cipriani@gmail.com
Guest
Posts: n/a
 
      06-05-2008
On Jun 4, 8:22 pm, Kai-Uwe Bux <(E-Mail Removed)> 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().

 
Reply With Quote
 
jason.cipriani@gmail.com
Guest
Posts: n/a
 
      06-05-2008
On Jun 4, 9:02 pm, "(E-Mail Removed)"
<(E-Mail Removed)> 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
 
Reply With Quote
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      06-05-2008
(E-Mail Removed) wrote:

> On Jun 4, 9:02 pm, "(E-Mail Removed)"
> <(E-Mail Removed)> 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
 
Reply With Quote
 
jason.cipriani@gmail.com
Guest
Posts: n/a
 
      06-08-2008
On Jun 5, 3:33 am, Kai-Uwe Bux <(E-Mail Removed)> 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
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Calling templated member of templated object david@sunlightd.com C++ 1 06-22-2007 05:13 PM
templated function as parameter of another templated function Amadeus W. M. C++ 2 07-04-2006 09:59 PM
ASP.NET Templated User Controls - Limit child controls allowable within a templated control JohnyStyles@gmail.com ASP .Net 0 05-29-2006 06:00 PM
Subtypes of templated types (in templated functions) Marijn C++ 5 02-13-2004 09:50 AM
implementing a templated struct within a templated struct RA Scheltema C++ 3 01-06-2004 11:25 AM



Advertisments