exception specifications
Nathan Sidwell
nathan@acm.org
Wed Mar 3 11:05:00 GMT 1999
Martin v. Loewis wrote:
> Well, they are sets. Sets can have different external representations,
> repeating elements still doesn't change the set, in the mathematil sense:
Aha, this is what I'd not thought about. I'd been thinking that the set and
it's external representation were isomorphic. Thus the types in the throw
specifier had one to one relationships with set members. What appears to be the
case is we construct the set of throw specifiers by set union with each
additional throw specifier.
> > 1) Are `throw(T)' and `throw(T, T)' the same?
> Yes. It looks like this is the reason for allowing duplicates.
Agree
> No. Since we've decided that the throw-spec is not a lexical thing,
> but semantical, it is very clear that {int, int} == {int}. Of course,
Agree
> > 2) Are `throw(T)' and `throw(T, U)' the same, if U is singly derived
> > from T? U is clearly redundant in the latter specification, but does
> > that cause it to match the former?
> No.
Agree
> > 3) Ditto for T *, U * and for T &, U &.
> Ditto.
Ditto.
> > 4) (2) and (3) are really asking if 15.4/6 actually means `according
> > to the matching semantics of catch clauses'. Then `T cv* cv' and `U
> > cv *cv' all come into the picture.
> They say mentioning subclasses is redundant, they don't lift the
> restriction in 15.4/2, which asks for identical sets. When they say
> 'redundant', they mean with regard to 15.4/7: The base class already
> allows the derived class.
Ok, clearing up 2 and 3 sorts this one out. I'd parsed 15.4/6 as "can include
the (same type more than once and can include classes that are related by
inheritance) even though doing so is redundant". I'd then jumped to the
conclusion that they were redundant for the same reason. That's not the case.
Duplicates are redundant because of set union, derrived classes are redundant
because of 15.4/7. Interestingly ptrs to derrived classes are not mentioned as
redundent, even though they are by 15.4/7. It's set union that concerns us
here.
> > 5) If you believe we're doing catch clause-like matching, then presumably we
> > should be ignoring the toplevel cv qualifiers of type-ids in the exception
> > specifier.
> We do not. 15.4/7 quite explicitly says what we do.
Yes fine. For some reason I'd missed that para, and went by 15.3/3 which says
how a handler is matched. Catching an exception (a catch clause) is different
to letting an exception escape from a function (an exception specifier). And
this of course clears up my confusion about ..
> > 6) If throw(int) and throw(const int) are different throw specifiers,
> > then 15.4/3 becomes strange. That says a virtual function overrider
> > "shall only allow exceptions that are allowed by the exception
> > specification of the base class virtual function". This is looser
> No, it doesn't. If the base method allows (int), the derived method
> can only *allow* (int) or (), but not (const int).
Agree.
Maybe I'm thinking about this too hard, but G++ does not seem to be paying
close attention to 15.4/7, I attach a program which I believe should call
unexpected(), but doesn't. From 15.1/3 I see a temporary object is constructed
whos type is the cv unqualified static type of the object of the throw
expression. Which type should be checked when trying to throw past the
function? That of the temporary or that of the throw expression? Looking at
fn3, that is throwing type 'Y *', yet the exception specification is 'X const *
const', that's not an X or X *, so shouldn't the final sentance of 15.4/7 apply
(exact match)?
This doesn't directly concern what I'm trying to implement, but I'd like to
know.
Thanks for the clarification Martin, that's given me sufficient intuits to get
going.
nathan
--
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
You can up the bandwidth, but you can't up the speed of light
nathan@acm.org http://www.cs.bris.ac.uk/~nathan/ nathan@cs.bris.ac.uk
void fn1()throw(const int &)
{int i = 0;throw i;}
void fn2()throw(int &)
{const int i = 0; throw i;}
struct X{};
struct Y: public X{};
void fn3()throw(X const * const)
{
static Y y;
throw &y;
}
int main()
{
try{fn1();}
catch(int &){}
try{fn2();}
catch(const int &){}
try{fn3();}
catch(X *){}
return 0;
}
More information about the Gcc
mailing list