Topic: Are exceptions thrown by static or dynamic type?
Author: sdouglass%_%junk@_cambridge.arm.com (scott douglass)
Date: 1997/08/01 Raw View
I only have the Dec 96 draft to go by. It seems to be contradictory, or at
least a bit "soft":
15.3 Handling an exception [except.handle]
"An object is
passed and the type of that object determines which handlers can catch
it."
The phrase "the type of that object" sounds like dynamic type. Unless
"that object" is the temporary object in the next bit:
"A _throw-expression_ initializes a temporary object, the type of which
is determined by removing any top-level _cv-qualifiers_ from the static
type of the operand of throw [...]"
This clearly says "static type".
15.3 Handling an exception [except.handle]
"A _handler_ is a match for a _throw-expression_ with an object of type E
if [...]"
The phrase "an object of type E" sounds like dynamic type, again.
I imagine that "the static type of the _throw-expression_" is what is meant
in each case. Especially since there's no mention of the object type being
polymorphic or not.
For argument's sake, here's an example. What gets printed?
#include <iostream>
struct B {
virtual void f(); // optional
};
struct D : B { };
void h(const B* b) { throw *b; }
void f(const B* b) { try { h(b); } catch (D&) { cout << "caught a D&\n"; } }
void f(const B* b) { try { g(b); } catch (B&) { cout << "caught a B&\n"; } }
int main()
{
D d;
f(&d);
return 0;
}
--scott
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.crud.com>
Date: 1997/08/04 Raw View
scott douglass wrote:
> For argument's sake, here's an example. What gets printed?
>
> #include <iostream>
>
> struct B {
> virtual void f(); // optional
> };
> struct D : B { };
>
> void h(const B* b) { throw *b; }
> void f(const B* b) { try { h(b); } catch (D&) { cout << "caught a D&\n"; } }
> void f(const B* b) { try { g(b); } catch (B&) { cout << "caught a B&\n"; } }
> int main()
> {
> D d;
> f(&d);
> return 0;
> }
(I'm assuming the first f should be g, right?)
The result is "caught a B&", because there is no polymorphism at the
throwing end of the exception mechanism, only at the catching end. I
think this is necessary because in practice it isn't always possible to
throw the actual object, since it may live on the stack beyond where it
must be cut back to by the exception. Therefore, the object must be
copied into a temporary, which requires that the compiler reduce it to
its static type.
If you throw a pointer instead of the object itself, it will still be
caught by the base class handler, since the compiler will generate code
that throws a B* even if it is a D*. However, inside the handler, it can
still be discovered at run time that the B* actually points to a D.
--
Ciao,
Paul
(Please remove the extra "crud" from the return address,
which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Steve Clamage <stephen.clamage@Eng.Sun.COM>
Date: 1997/08/04 Raw View
scott douglass wrote:
>
> I only have the Dec 96 draft to go by. It seems to be contradictory, or at
> least a bit "soft":
>
> 15.3 Handling an exception [except.handle]
> "An object is
> passed and the type of that object determines which handlers can catch
> it."
>
> The phrase "the type of that object" sounds like dynamic type. Unless
> "that object" is the temporary object in the next bit:
>
> "A _throw-expression_ initializes a temporary object, the type of which
> is determined by removing any top-level _cv-qualifiers_ from the static
> type of the operand of throw [...]"
>
> This clearly says "static type".
When an object is created, the static and dynamic types of the
object are always the same and cannot be changed (without invoking
undefined behavior). The terms "static type" and "dynamic type"
can be applied usefully only to the referent of a pointer or
reference. Since the draft is talking about objects being created,
there is no question about the type.
--
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Srinivas Vobilisetti <Srinivas.Vobilisetti@mci.com>
Date: 1997/08/04 Raw View
scott douglass wrote:
>
> I only have the Dec 96 draft to go by. It seems to be contradictory, or at
> least a bit "soft":
>
> 15.3 Handling an exception [except.handle]
> "An object is
> passed and the type of that object determines which handlers can catch
> it."
>
> The phrase "the type of that object" sounds like dynamic type. Unless
> "that object" is the temporary object in the next bit:
>
> "A _throw-expression_ initializes a temporary object, the type of which
> is determined by removing any top-level _cv-qualifiers_ from the static
> type of the operand of throw [...]"
>
> This clearly says "static type".
Yes you are right.
> 15.3 Handling an exception [except.handle]
> "A _handler_ is a match for a _throw-expression_ with an object of type E
> if [...]"
>
> The phrase "an object of type E" sounds like dynamic type, again.
Take the following class heriarchy.
class B { /*.....*/ };
class C : public B { /*.....*/ };
class D : public C { /*.....*/ };
f(const C &c)
{
throw c;
}
g(const C &c)
{
try {
f(c);
}
catch(const D &rd) {
cout << "caught an exception of type D";
}
catch(const B &rb) {
cout << "caught an exception of type B";
}
}
int main()
{
D d;
g(d);
return 0;
}
The output of the above program is "caught an exception of type B".
Though, the dynamic type of c in f() is D, its static type is C. So, an
object of type C is thrown. In g(), as C is not a D but C is a B, the
second catch block will be entered.
> I imagine that "the static type of the _throw-expression_" is what is meant
> in each case. Especially since there's no mention of the object type being
> polymorphic or not.
>
> For argument's sake, here's an example. What gets printed?
>
> #include <iostream>
>
> struct B {
> virtual void f(); // optional
> };
> struct D : B { };
>
> void h(const B* b) { throw *b; }
> void f(const B* b) { try { h(b); } catch (D&) { cout << "caught a D&\n"; } }
==> I assume the above function f(const B *) is indeed g(const B *)
> void f(const B* b) { try { g(b); } catch (B&) { cout << "caught a B&\n"; } }
> int main()
> {
> D d;
> f(&d);
> return 0;
> }
> --scott
> ---
The output will be "caught a B&". I ignored the newline character at the
end.
Srinivas
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Steve Clamage <stephen.clamage@Eng.Sun.COM>
Date: 1997/08/07 Raw View
scott douglass wrote:
>
> In article <33E614A8.7310@Eng.Sun.COM>, Steve Clamage
> <stephen.clamage@Eng.Sun.COM> wrote:
>
> > When an object is created, the static and dynamic types of the
> > object are always the same and cannot be changed (without invoking
> > undefined behavior). The terms "static type" and "dynamic type"
> > can be applied usefully only to the referent of a pointer or
> > reference. Since the draft is talking about objects being created,
> > there is no question about the type.
>
> I agree, there's no question about the type of the temporary object. There
> are two objects involved in throwing an exception: the one that is the
> value of the _throw-expression_ and the temporary object discussed in
> [except.throw].
>
> I guess what isn't clear is that the object referred to in "A handler is a
> match for a _throw-expression_ with an object of type E if [...]" in
> [except.handle] is the temporary object and is not the object that is the
> value of the _throw-expression_.
>
> Similarly in "An object is passed and the type of that object determines
> which handlers can catch it." in [except.throw] the object referred to must
> be the temporary object.
A throw-expression always throws an object by value, no matter
how the object might be caught. In general, the object thrown is a
copy (a temporary object) of the value of the throw-expression. That
object has the same type as the throw-expression except that arrays
and functions are converted to pointers. The whole process works
just like passing an actual argument to a function's formal parameter,
except that throwing an exception makes an extra copy of the value.
(The extra copy can sometimes be optimized away.)
The object is used to initialize the handler's variable. The type of
the thrown temporary (like an actual parameter) does not depend on the
type of the handler variable (like a formal parameter) which receives
it.
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]