Topic: Exceptions


Author: abell8920@mindspring.com (Andrew Bell)
Date: 1998/03/24
Raw View
[Moderator: I sent this out on Friday.  It shows up as sent in my
newsreader's outbox.  However, it hasn't appeared on my site or
DejaNews.]

On 19 Mar 98 14:49:20 GMT, Stefan Rupp <struppi@gia.rwth-aachen.de>
wrote:
>On 18 Mar 98 17:34:41 GMT, msherman@magma.ca (Marc Sherman) wrote:
>> And, if your compiler is any good, it will warn you when you compile
>> that g is calling a function with looser exception specifications without
>> an appropriate try/catch block.

>If there is no exception-specification in the function signature, the
>function may or may not throw an exception. So the compiler does not
>know if the function throws an exception at all. Think of existing
>libraries, which don't specify the exception which can be thrown by
>its functions.

And with good reason.  Without compiler warnings, if you add throw
specifiers you might as well replace throws with exit() statements and
be done with it.  Moreover, any function that has a throw() specifier
that doesn't trap all the exceptions it or functions it calls might
possibly throw, it has to have the overhead of catching anything and
calling unexpected().

I'd love to have a compiler that warns me as Marc suggests (I've sent
a suggestion to the Microsoft Visual C++ team to this effect), and has
an option to IGNORE throw specifiers otherwise.  It's just about the
only C++ feature that I wish I could get rid of.

--Andrew Bell
---
[ 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: Ross Smith <ross.smith@nz.eds.com>
Date: 1998/03/24
Raw View
Marc Sherman wrote:
>
> And, if your compiler is any good, it will warn you when you compile
> that g is calling a function with looser exception specifications without
> an appropriate try/catch block.
>
> [ ... ]
>
> Which is why it should be a warning, not an error, and is not mandated
> by the standard.  However, it is a very useful warning, that every
> compiler should emit.

I don't agree. It's common (at least the way I code) for code to check
or transform its arguments and proceed only when it's in a consistent
state, so that subsequent function calls are known not to throw. Warning
every time a function with a looser exception spec is called without a
guard would give far too many false positives to be useful.

A trivial example (for illustrative purposes pretend there's no
std::sqrt() function):

    double square_root(double x) throw (domain_error) {
      if (x < 0) throw domain_error();
      return std::pow(x, 0.5);
    }

    double pythagoras(double x, double y) throw () {
      return square_root(x * x + y * y);
    } // ... Bzzt! false warning

--
Ross Smith ............................. <mailto:ross.smith@nz.eds.com>
Internet and New Media, EDS (New Zealand) Ltd., Wellington, New Zealand
"Isn't it interesting that the same people who laugh at science fiction
listen to weather forecasts and economists?" -- Kelvin Throop III
---
[ 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: abell8920@mindspring.com (Andrew Bell)
Date: 1998/03/25
Raw View
On 24 Mar 98 17:47:38 GMT, Ross Smith <ross.smith@nz.eds.com> wrote:
>It's common (at least the way I code) for code to check
>or transform its arguments and proceed only when it's in a consistent
>state, so that subsequent function calls are known not to throw.

I'd hope that any compiler that implemented such a warning to be able
to disable it with a pragma.

>    double pythagoras(double x, double y) throw () {
>      return square_root(x * x + y * y);
>    } // ... Bzzt! false warning

The problem is, unless the compiler has access to the definition of
square_root and is very smart, it will have to implement pythagoras as
if it were:

double pythagoras(double x, double y) throw () {
 try {
       return square_root(x * x + y * y);
 }
 catch (domain_error) {
  while (1) {
   try {
    unexpected();
   }
   catch (domain_error) {
   }
  }
 }
}

You won't see this as a programmer, but object-code-wise it will be
there.  That's a lot of extra object code just for adding a throw
specifier, and could discourage people from using throw() specifiers
to begin with.

If the compiler has the smarts to figure out that square_root won't
throw and thus not add the extra code, it's smart enough to not give
the "violated throw specifier" warning Marc Sherman and I would like
anyway.

Ideally, we'd have some sort of preconditions stated in the interface,
and a smart compiler.  In that case, the > 0 test in square_root would
be a precondition, and thus known to the compiler as it compiles
pythagoras().  If the compiler is smart enough to realize that x * x
is > 0 for all x (at least for doubles -- note that for integer types
overflow is a possibility), and the sum of positive doubles is > 0,
the precondition will always be satisfied.

--Andrew Bell
---
[ 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: msherman@magma.ca (Marc Sherman)
Date: 1998/03/27
Raw View
>On 24 Mar 98 17:47:38 GMT, Ross Smith <ross.smith@nz.eds.com> wrote:
[common sqrt(int pos) example snipped]

Andrew Bell <abell8920@mindspring.com> wrote:
>Ideally, we'd have some sort of preconditions stated in the interface,
>and a smart compiler.  In that case, the > 0 test in square_root would
>be a precondition, and thus known to the compiler as it compiles
>pythagoras().  If the compiler is smart enough to realize that x * x
>is > 0 for all x (at least for doubles -- note that for integer types
>overflow is a possibility), and the sum of positive doubles is > 0,
>the precondition will always be satisfied.

That might be ideal, but it's very foreign to what C++ currently is.
Last time this discussion came up, I suggested a throw_cast<x-list>(func)
be added to tell the compiler that I know that func will only throw
the exceptions in x-list in this particular use.  Using it will
suppress both the warning message and the extraneous try/catch/unexpected
code around the call.  Throwing an exception from func that is not
in x-list is undefined behaviour, not required to call unexpected, allowing
for better optimization.  As with other casts, the long obtuse name
balances the risk, and the user is trusted to know what they're doing.

Someone interfacing throw-correct client code to throw-incorrect library
code could then write a set of inline wrappers that cast the library
functions to have the appropriate throw specifications before calling
them -- this is very analogous to the case of wrapping const-incorrect
library functions with const-correct inlines which use const_cast to call
through.  It is obviously up to the author of the wrappers to inspect the
library code and ensure that it conforms to the new throw or const
guarantees.

- Marc
---
[ 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: msherman@magma.ca (Marc Sherman)
Date: 1998/03/18
Raw View
>Stefan Rupp wrote:
>> Now I wonder what happens in the following case:
>>
>>   void h() { // may throw any kind of exception
>>     throw Y;
>>   }
>>
>>   void g() throw ( X ) {
>>     h();
>>   }

Srinivas Vobilisetti  <srinivas-v@usa.net> wrote:
>As you pointed out from CD2, the exception specification of g() does not
>allow exceptions of type Y. So, the function unexpected() is called.

And, if your compiler is any good, it will warn you when you compile
that g is calling a function with looser exception specifications without
an appropriate try/catch block.

By this definition, are there any good compilers available yet?

- Marc
---
[ 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: Stefan Rupp <struppi@gia.rwth-aachen.de>
Date: 1998/03/19
Raw View
Good afternoon,

msherman@magma.ca (Marc Sherman) writes:
> >Stefan Rupp wrote:
> >> Now I wonder what happens in the following case:
> >>
> >>   void h() { // may throw any kind of exception
> >>     throw Y;
> >>   }
> >>
> >>   void g() throw ( X ) {
> >>     h();
> >>   }
>
> Srinivas Vobilisetti  <srinivas-v@usa.net> wrote:
> >As you pointed out from CD2, the exception specification of g() does not
> >allow exceptions of type Y. So, the function unexpected() is called.
>
> And, if your compiler is any good, it will warn you when you compile
> that g is calling a function with looser exception specifications without
> an appropriate try/catch block.

If there is no exception-specification in the function signature, the
function may or may not throw an exception. So the compiler does not
know if the function throws an exception at all. Think of existing
libraries, which don't specify the exception which can be thrown by
its functions.

Ciao,
     struppi

--
Dipl.-Inform. Stefan H. Rupp
Geodaetisches Institut der RWTH Aachen         Email: struppi@acm.org
Templergraben 55, D-52062 Aachen, Germany      Tel.:  +49 241 80-5295
---
[ 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: msherman@magma.ca (Marc Sherman)
Date: 1998/03/19
Raw View
>msherman@magma.ca (Marc Sherman) writes:
>> And, if your compiler is any good, it will warn you when you compile
>> that g is calling a function with looser exception specifications without
>> an appropriate try/catch block.

Stefan Rupp  <struppi@gia.rwth-aachen.de> wrote:
>If there is no exception-specification in the function signature, the
>function may or may not throw an exception. So the compiler does not
>know if the function throws an exception at all. Think of existing
>libraries, which don't specify the exception which can be thrown by
>its functions.

Which is why it should be a warning, not an error, and is not mandated
by the standard.  However, it is a very useful warning, that every
compiler should emit.  The only safe way to use a function with no
exception specification is to assume that it throws any kind of
exception, and therefore wrap it in a catch(...) statement if you're
calling it from a function that promises to throw a limited set of
exceptions.

By providing the warning, the compiler is telling you at compile time
that there is a possibility that your application will abort by
calling unexpected at runtime.  I'd much rather find out about the
possibility at compile time than find out from the customer after
I've shipped the app.

- Marc



[ 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: Stefan Rupp <struppi@gia.rwth-aachen.de>
Date: 1998/03/17
Raw View
Good afternoon,

the CD2 says in section 15.4 (Exception specifications [except.spec]) that:

8 Whenever  an  exception  is  thrown  and  the  search  for  a  handler
  (_except.handle_) encounters the outermost block of a function with an
  exception-specification,   the   function   unexpected()   is   called
  (_except.unexpected_) if the exception-specification  does  not  allow
  the exception.  [Example:

          class X { };
          class Y { };
          class Z: public X { };
          class W { };

          void f() throw (X, Y)
          {
              int n = 0;
              if (n) throw X();        // OK
              if (n) throw Z();        // also OK
              throw W();               // will call unexpected()
          }
   --end example]

Now I wonder what happens in the following case:

  void h() { // may throw any kind of exception
    throw Y;
  }

  void g() throw ( X ) {
    h();
  }

  void f() {
    try {
      g();
    }
    catch ( ... ) {
      // do emergency clean-up
    }
  }

Should unexpected() be called or the outermost catch(...) block in
function f()?  The latest GNU C++ compiler 2.8.0 calls unexpected()
which seems like an error to me.

Ciao,
     struppi

--
Dipl.-Inform. Stefan H. Rupp
Geodaetisches Institut der RWTH Aachen         Email: struppi@acm.org
Templergraben 55, D-52062 Aachen, Germany      Tel.:  +49 241 80-5295
---
[ 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: Srinivas Vobilisetti <srinivas-v@usa.net>
Date: 1998/03/18
Raw View
Stefan Rupp wrote:
>
> Good afternoon,
>
> the CD2 says in section 15.4 (Exception specifications [except.spec]) that:
>
> 8 Whenever  an  exception  is  thrown  and  the  search  for  a  handler
>   (_except.handle_) encounters the outermost block of a function with an
>   exception-specification,   the   function   unexpected()   is   called
>   (_except.unexpected_) if the exception-specification  does  not  allow
>   the exception.  [Example:
>
>           class X { };
>           class Y { };
>           class Z: public X { };
>           class W { };
>
>           void f() throw (X, Y)
>           {
>               int n = 0;
>               if (n) throw X();        // OK
>               if (n) throw Z();        // also OK
>               throw W();               // will call unexpected()
>           }
>    --end example]
>
> Now I wonder what happens in the following case:
>
>   void h() { // may throw any kind of exception
>     throw Y;
>   }
>
>   void g() throw ( X ) {
>     h();
>   }

As you pointed out from CD2, the exception specification of g() does not
allow exceptions of type Y. So, the function unexpected() is called.

<snip>

Srinivas
---
[ 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: Andrew Gierth <andrew@erlenstar.demon.co.uk>
Date: 1998/03/18
Raw View
>>>>> "Stefan" == Stefan Rupp <struppi@gia.rwth-aachen.de> writes:

 Stefan> 8 Whenever an exception is thrown and the search for a
 Stefan>   handler (_except.handle_) encounters the outermost block of a
 Stefan>   function with an exception-specification, the function
 Stefan>   unexpected() is called (_except.unexpected_) if the
 Stefan>   exception-specification does not allow the exception.

 Stefan> Now I wonder what happens in the following case:

 Stefan>   void h() { // may throw any kind of exception
 Stefan>     throw Y;
 Stefan>   }

 Stefan>   void g() throw ( X ) {
 Stefan>     h();
 Stefan>   }

 Stefan>   void f() {
 Stefan>     try {
 Stefan>       g();
 Stefan>     }
 Stefan>     catch ( ... ) {
 Stefan>       // do emergency clean-up
 Stefan>     }
 Stefan>   }

 Stefan> Should unexpected() be called or the outermost catch(...)
 Stefan> block in function f()?  The latest GNU C++ compiler 2.8.0
 Stefan> calls unexpected() which seems like an error to me.

The call to unexpected() is correct.

When Y is thrown, the search for a handler begins in function h(),
fails to find one, thus propagates outward to function g(). At this
point it encounters the exception-specification that allows only X,
so unexpected() is called as per the cited text from the standard.

The intent is that an exception-specification defines what exceptions
may propagate outward from that function.

--
Andrew.
---
[ 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: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1998/03/18
Raw View
In article fsf@gameboy.gia.rwth-aachen.de, Stefan Rupp <struppi@gia.rwth-aachen.de> writes:
>
>the CD2 says in section 15.4 (Exception specifications [except.spec]) that:
>
>8 Whenever  an  exception  is  thrown  and  the  search  for  a  handler
>  (_except.handle_) encounters the outermost block of a function with an
>  exception-specification,   the   function   unexpected()   is   called
>  (_except.unexpected_) if the exception-specification  does  not  allow
>  the exception.
>
>Now I wonder what happens in the following case:
>
>  void h() { // may throw any kind of exception
>    throw Y;
>  }
>
>  void g() throw ( X ) {
>    h();
>  }
>
>  void f() {
>    try {
>      g();
>    }
>    catch ( ... ) {
>      // do emergency clean-up
>    }
>  }
>
>Should unexpected() be called ...

Yes, because of the part of the draft you quoted.

Function g is allowed to throw an X or anything derived from X.
When g runs, it calls h, which throws a Y, which we will assume
is not derived from X. Function g does not catch the Y internally,
and is not allowed to exit via a Y, so unexpected must be called
at the point where g would exit via the Y.

It doesn't matter that function f is willing to handle the Y,
because g is not allowed to throw the Y.

---
Steve Clamage, stephen.clamage@sun.com
---
[ 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: Stefan Rupp <struppi@gia.rwth-aachen.de>
Date: 1998/03/18
Raw View
Good morning,

clamage@Eng.Sun.COM (Steve Clamage) writes:
> >Should unexpected() be called ...
>
> Yes, because of the part of the draft you quoted.

OK. Thanks to you and all the others who answered.  I guess I
misinterpreted the word "outermost" in the CD2.

Ciao,
     struppi

--
Dipl.-Inform. Stefan H. Rupp
Geodaetisches Institut der RWTH Aachen         Email: struppi@acm.org
Templergraben 55, D-52062 Aachen, Germany      Tel.:  +49 241 80-5295
---
[ 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: rogerson@PEDEV.Columbia.NCR.COM (Dale Rogerson)
Date: 20 Aug 90 19:39:20 GMT
Raw View
Could someone please give an overview of the current status of
exceptions in C++?  What is the current proposed syntax? When
are these features likely to be added to the language?

Thanks
-----Dale
 Rogerson-----