This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Adding to G++: Adding a warning on throwing unspecified exceptions.


Brendon Costa wrote:
> You as an author of a new template class "could" define it the other way.
>
> The issue here is that doing so restricts usage of the generic
> component. In specific cases this may be desirable, but not for generic
> components like STL containers or those in boost. For generic components
> you want to make them as useful as possible. Even if at the time of
> writing the container you do not foresee that throwing any type of
> exception is a good idea, users may come up with some way of using it
> that you just never thought about.
>
> I.e. I think the general philosophy is to define only what restrictions
> are necessary to implement the template, not necessarily what we think
> constitute good uses of the template at the time we created it.

I definately agree with your comments here (generic components should
often allow their types to throw what they like), I'm just not sure
how to achieve it any other way.



Here's some ideas:

1) In many cases, templates can make a pretty good case for requiring
no-throw for member functions of their type, such as destructors and
move constructors.
Currently, templates can't restrict exceptions when they should and
when they shouldn't.
With the warning, templates need to restrict exceptions when they
should and when they shouldn't, (or be throw all, which requires an
ugly downstream catch(...) ).
Both aren't optimal, although preventing a legitimate thing is worse
than allowing a wrong thing.


2) As in my last post, use template parameters to specify additional
exception types.
===================================
#include <iostream>

class foo {
  public:
    void bar() throw(float) { throw float(5); }
};

template <typename F> // or use concepts.
class zug {
  public:
    template <typename E> void call_bar() throw(int, E) { f.bar();
throw int(3); }
    F f;
};

int main() {
    zug<foo> zf;
    try {
        zf.call_bar<float>(); // here float is passed as an additional
exception.
    }
    catch(int& caught) {
        std::cout << "caught an int" << std::endl;
    }
    catch(float& caught) {
        std::cout << "caught a float" << std::endl;
    }
    return 0;
}
===================================
output:
caught a float
===================================
The above works on code::blocks, which uses some form of GCC, and
looks OK to me.
Of course this only works for exactly one exception type.
You'd have to wait for C++0X variadic templates (and hope you can
throw them) if you need zero or more than one.
It's also very verbose, a little cryptic, and nested templates could
make variadic versions horrifically long.
However it's a start.


Brendon Costa wrote:
> I had to go to lengths to provide
> a "suppressions" system for EDoc++, simply because almost all code can
> throw all sorts of exceptions i had never heard of before. A developer
> "generally" is not interested in exceptions like:
> __gnu_cxx::recursive_init. But after writing EDoc++ i found exceptions
> like this turn up all over the place, though they should not occur in
> normal operation...
As for implicit exceptions that aren't manually thrown with a throw
statement, eg:
__gnu_cxx::recursive_init
(http://www.cygwin.com/ml/cygwin-developers/2005-05/msg00019.html)
or arithmetic exceptions (perhaps 1/0 etc)
I would just suggest ignoring these. Eventually the compiler _may_
declare these exceptions per implicit op or remove the exceptions, but
either way it's too difficult to manage manually.
You could still specify those exceptions if you're really masochistic.



There is something else to consider.
If this project works reasonably well and perhaps becomes popular,
it's not unreasonable to suggest some minor extensions to the C++
standard to help people code using it.
For example:
1) allowing typedef'd function pointers and concept functions to have
a throw specifier.
2) allowing: "void bar() throw(type_a, type_b, foo::throw);" or "...,
foo())" or something whereby bar inherits foo's throw specifiers,
which would mainly solve the above template problem.
3) extending 2 by giving the option of removing specific types, "void
bar() throw(foo::throw, not int);" so that you can reduce the types
thrown by catching them. I can think of some circumstances where this
could be useful but I'm not sure if they're common enough to justify
it.
Which would then make rigid exception specifying easy enough to use
everywhere. Ok I know I'm trying to fly before I can crawl here :)
Just something to think on.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]