Topic: Exception class


Author: AllanW@my-dejanews.com
Date: 1999/01/20
Raw View
In article <36A051D2.73CC3F81@bigfoot.com>,
  Shiva <jshiva@bigfoot.com> wrote:
> Hi,
>  The standard in section 15.3 says this
[snip]
> I take the statement about the incomplete type to mean that you
> can't have something like
>
> class Err; // forward declaration.
> try
> {
>  f();
> }
> catch(Err & e)
> {/* */}
>
> Am I right ?

That's how I read it.

> But I tried something like this is in both MSVC & EGCS & it was
> allowed !!!

This surprises you?

Both compilers allow many examples of code which are nonetheless
not legal C++. You were wise to notice that this is not legal
code, because it won't work on all C++ compilers.

Remember, the standard specifies the minimum that all C++ compilers
must compile. The compiler is allowed to accept other programs as
well, if it wants to; in this case, we have a program that looks a
lot like a valid C++ program, until you look very very closely.

I didn't see anything that allows the compiler to skip the
diagnostic for this error. So probably some future version of MSVC
and/or EGCS will catch this error, and at least print a warning.

> Anyway why is this restriction there ?
> The handler is catching the object by reference,
> & hence not creating a new object. So why can't it
> work with a reference ?

This I'm not so sure about; I'm guessing here:

You don't know anything about variable e. How big is class Err?
Does it have any virtual functions? In general, you can't define
any code that uses class Err until you completely declare class
Err. For instance, this is also illegal:
    class Err;
    int func(Err &e)
    {
        Err e2(e); // Do we have a public copy constructor?
    }
"But I'm not doing anything to the object except referring to it!"
That's probably why it didn't fail on MSVC and/or EGCS. But it's
still illegal.

----
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jshiva@bigfoot.com
Date: 1999/01/18
Raw View
In article <slrn7a4o71.cf.sbnaran@localhost.localdomain>,
  sbnaran@uiuc.edu wrote:
> // include.h
> struct Base;
> struct Derived;
> void f();
>
> // include.c
> #include "include.h"
> struct Base { };
> struct Derived : Base { };
> void f() { throw Derived(); }
>
> // main.c
> #include "include.h"
> #include <iostream.h>
> int main()
> {
>    try
>    {
>       cout << "start try\n";
>       f();
>       cout << "end try\n";
>    }
>    catch(Base   & b) { cout << "caught Base\n"   ;}
>    catch(Derived& d) { cout << "caught Derived\n";}
> }
>
> -------------------------------------------------------------------------=
[ snipped como's warning msg ]
> (BTW, what a nice warning message!)  But como compiles it and
> actually generates the correct results.  The output is
>
>    start try
>    caught Base
>
> I'm confused as to why the program works.  Because the file
> main.o does not know anything of class Base and class Derived,
> and whether they are related by inheritance.  So how does the
> program know which catch clause to use?  My guess should be
> that the program should not compile.  But if it compiles, then
> no catch clause matches the thrown exception and the program
> should abort with an unhandled exception.
>
> My guess is that the compiler does additional compiling at
> link time, and at this point, it realizes what class Base and
> class Derived are, and that they are related by inheritance.
> Since class Base and class Derived have external linkage,
> this compiling at link time seems reasonable.  But it's work
> that the compiler writers didn't have to go through.
>

No. I don't think your explanation is correct. I think, it works because
the type check happens at run time rather than compile time. At run time,
the type is checked as
Base * ptr = dynamic_cast<Base *>(&b). // Taken from Valentin Bonard's post
 // in the same thread.
This succeeds, so the catch handler is executed.

cheers,
Shiva
comp.lang.c++ FAQ :http://www.cerfnet.com/~mpcline/c++-faq-lite/
http://members.xoom.com

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/18
Raw View
Shiva wrote:

>         The standard in section 15.3 says this
> "[except. handle] 15.3 Handling an exception
> 1 The exception    declaration in a handler describes the type( s) of exceptions that can cause that
> handler to be
> entered. The exception    declaration shall not denote an incomplete type. The exception    declaration
> shall
> not denote a pointer or reference to an incomplete type, other than void*, const void*, volatile
> void*, or const volatile void*. Types shall not be defined in an exception    declaration. "
>
> I take the statement about the incomplete type to mean that you can't have something
> like
>
> class Err; // forward declaration.
>
> try
> {
>         f();
> }
> catch(Err & e)
> {/* */}
>
> Am I right ?
>
> But I tried something like this is in
> both MSVC & EGCS & it was allowed !!!
>
> Anyway why is this restriction there ?
> The handler is catching the object by reference,
> & hence not creating a new object. So why can't it
> work with a reference ?

Because that's the rules for dynamic_cast (BTW dynamic_cast never
creates new objects); the code can be translated:

try {
    f ();
}
catch (object& ob) // object is a universal super class
{
    if (Err* p = dynamic_cast<Err*> (&e))
        /*   */
    else
        throw;
}

But if you write:

try {
    f ();
}
catch (Err*&)
{}

then it is correct and translates to

try {
    f ();
}
catch (object& ob) // object is a universal super class
{
    if (typeid (ob) == typeid (Err*))
        /*   */
    else
        throw;
}

Anyway, using an incomplete type is strange, because then you
won't be able to call the member functions of the exception
object to find the cause of the problem (like exception::what ()).

If you don't care about the cause of the problem you can
use ... anyway.

Exceptions are simple objects and including the corresponding
header probably won't be expensive.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/01/18
Raw View
jshiva@bigfoot.com wrote:
>
> In article <slrn7a4o71.cf.sbnaran@localhost.localdomain>,
>   sbnaran@uiuc.edu wrote:

[...]

> > I'm confused as to why the program works.  Because the file
> > main.o does not know anything of class Base and class Derived,
> > and whether they are related by inheritance.  So how does the
> > program know which catch clause to use?  My guess should be
> > that the program should not compile.  But if it compiles, then
> > no catch clause matches the thrown exception and the program
> > should abort with an unhandled exception.
> >
> > My guess is that the compiler does additional compiling at
> > link time, and at this point, it realizes what class Base and
> > class Derived are, and that they are related by inheritance.
> > Since class Base and class Derived have external linkage,
> > this compiling at link time seems reasonable.  But it's work
> > that the compiler writers didn't have to go through.
> >
>
> No. I don't think your explanation is correct. I think, it works because
> the type check happens at run time rather than compile time. At run time,
> the type is checked as
> Base * ptr = dynamic_cast<Base *>(&b). // Taken from Valentin Bonard's post
>  // in the same thread.
> This succeeds, so the catch handler is executed.

May dynamic_cast used on incomplete types? I doubt so.
Even (Base*)pDerived may give a false result if the compiler
doesn't know that Derived is derived from Base.
Also, the compiler cannot know if Base has a vtbl at all,
if it doesn't know at least the definition of class Base.
So even a dynamic_cast needs some static info to start with.
Also, dynamic_cast needs the type_info record, and AFAIK
typeid is an operator which may not be used on incomplete types.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Shiva <jshiva@bigfoot.com>
Date: 1999/01/17
Raw View
Hi,
 The standard in section 15.3 says this
"[except. handle] 15.3 Handling an exception=20
1 The exception=AD declaration in a handler describes the type( s) of exc=
eptions that can cause that
handler to be=20
entered. The exception=AD declaration shall not denote an incomplete type=
. The exception=AD declaration
shall=20
not denote a pointer or reference to an incomplete type, other than void*=
, const void*, volatile=20
void*, or const volatile void*. Types shall not be defined in an exceptio=
n=AD declaration. "

I take the statement about the incomplete type to mean that you can't hav=
e something
like

class Err; // forward declaration.

try
{
 f();
}
catch(Err & e)=20
{/* */}

Am I right ?

But I tried something like this is in
both MSVC & EGCS & it was allowed !!!

Anyway why is this restriction there ?
The handler is catching the object by reference,
& hence not creating a new object. So why can't it
work with a reference ?

--=20
cheers,
Shiva
comp.lang.c++ FAQ: http://www.cerfnet.com/~mpcline/c++-faq-lite/
http://members.xoom.com/jshiva/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Ian Collins <ian@masuma.com>
Date: 1999/01/18
Raw View
Shiva wrote:
>
> Hi,
>         The standard in section 15.3 says this
> "[except. handle] 15.3 Handling an exception
> 1 The exception-declaration in a handler describes the type(s) of exceptions
> that can cause that handler to be
> entered. The exception    declaration shall not denote an incomplete type.
> The exception-declaration shall
> not denote a pointer or reference to an incomplete type, other than void*,
> const void*, volatile void*, or const volatile void*.
> Types shall not be defined in an exception    declaration. "
>
> I take the statement about the incomplete type to mean that you can't
> have something like
>
> class Err; // forward declaration.
>
> try
> {
>         f();
> }
> catch(Err & e)
> {/* */}
>
> Am I right ?
>
Yes!

> But I tried something like this is in
> both MSVC & EGCS & it was allowed !!!
>
No comment.

> Anyway why is this restriction there ?
> The handler is catching the object by reference,
> & hence not creating a new object. So why can't it
> work with a reference ?
>
Because it does not know how to work out what Err is, it can't use any
RTTI info to determine if an
exception is of class Err.

Sun CC5.0 spits this out! (Error: The type "Err" is incomplete.)

--
Ian Collins
Violet Cottage, Button End
Harston, Cambs
UK.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/01/18
Raw View
On 17 Jan 99 02:46:16 GMT, Shiva <jshiva@bigfoot.com> wrote:

> The standard in section 15.3 says this
>"[except. handle] 15.3 Handling an exception=20
>1 The exception=AD declaration in a handler describes the type( s) of
>exceptions that can cause that handler to be entered. The exception=AD
>declaration shall not denote an incomplete type. The exception=AD
>declaration shall not denote a pointer or reference to an incomplete
>type, other than void*, const void*, volatile void*, or const volatile
>void*. Types shall not be defined in an exception=AD declaration. "


Interesting.  I doubt that it is a problem in practice as we would
surely want to use the caught object inside the body of our 'catch'
clause, and this means that the class definition of typeof(object)
should be present.

Assuming the above rule is correct, here is a faulty program.

-------------------------------------------------------------------------=
-

// include.h
struct Base;
struct Derived;
void f();

// include.c
#include "include.h"
struct Base { };
struct Derived : Base { };
void f() { throw Derived(); }


// main.c
#include "include.h"
#include <iostream.h>
int main()
{
   try
   {
      cout << "start try\n";
      f();
      cout << "end try\n";
   }
   catch(Base   & b) { cout << "caught Base\n"   ;}
   catch(Derived& d) { cout << "caught Derived\n";}
}

-------------------------------------------------------------------------=
-

Function main(...) in main.c uses incomplete types 'Base' and
'Derived' in its catch clauses.  This means that the compiler can't
give use the useful warning message
   catch(Base&) hides catch(Derived&) -- ie, all 'Base' and
   'Derived' error objects will be handled by the first catch
   clause.
(BTW, what a nice warning message!)  But como compiles it and
actually generates the correct results.  The output is

   start try
   caught Base



I'm confused as to why the program works.  Because the file
main.o does not know anything of class Base and class Derived,
and whether they are related by inheritance.  So how does the
program know which catch clause to use?  My guess should be
that the program should not compile.  But if it compiles, then
no catch clause matches the thrown exception and the program
should abort with an unhandled exception.

My guess is that the compiler does additional compiling at
link time, and at this point, it realizes what class Base and
class Derived are, and that they are related by inheritance.
Since class Base and class Derived have external linkage,
this compiling at link time seems reasonable.  But it's work
that the compiler writers didn't have to go through.

--=20
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]