Is it legal to throw exceptions from ?: expressions?

Is it legal to throw exceptions from ?: expressions?

Post by Esa » Wed, 15 May 2002 16:56:49



While porting some C++ code from Digital C++ to Microsoft Visual C++ I game
across code that looks like this:

int x;
bool y = x != 0 ? x : throw std::range_error("aaargh...");

VC++ gives the following error:

error C2440: 'initializing' : cannot convert from 'void' to 'bool'
        Expressions of type void cannot be converted to other types

Digital C++ compiles it without complaints.
Is this valid C++ or a compiler bug in VC++?
Is throw an expression that returns a void?

Esa


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by Erik Max Franci » Wed, 15 May 2002 20:49:13



> int x;
> bool y = x != 0 ? x : throw std::range_error("aaargh...");

> VC++ gives the following error:

> error C2440: 'initializing' : cannot convert from 'void' to 'bool'
>         Expressions of type void cannot be converted to other types

> Digital C++ compiles it without complaints.
> Is this valid C++ or a compiler bug in VC++?

It is illegal in C++; VC++ is correct (for once).  throw is a statement,
not an expression.  In a conditional expression, both the true and false
expressions must have the same type.

--

 __ San Jose, CA, US / 37 20 N 121 53 W / ICQ16063900 / &tSftDotIotE
/  \ Who'd ever think it / Such a squalid little ending
\__/ The American and Florence, _Chess_
    Church / http://www.alcyone.com/pyos/church/
 A lambda calculus explorer in Python.


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by James Kanz » Wed, 15 May 2002 21:24:31


|>  While porting some C++ code from Digital C++ to Microsoft Visual
|>  C++ I game across code that looks like this:

|>  int x;
|>  bool y = x != 0 ? x : throw std::range_error("aaargh...");

|>  VC++ gives the following error:

|>  error C2440: 'initializing' : cannot convert from 'void' to 'bool'
|>          Expressions of type void cannot be converted to other types

|>  Digital C++ compiles it without complaints.
|>  Is this valid C++ or a compiler bug in VC++?

It is valid C++, and there is a bug in VC++ for not accepting it.

|>  Is throw an expression that returns a void?

Yes.  But there is no place where you attempt to convert this void to
bool.  What you are attempting to convert to bool is the results of
the ?: operator.  And according to the standard (5.16/3):

    If either the second or the third operand has type void, [...],
    and one of the following shall hold:

     -- The second or the third operand (but not both) is a
        throw-expression; the result is of the type of the other, and
        is an rvalue.

In this case, the result of ?: is of type int, and you can convert an
int to a bool.

--

Conseils en informatique oriente objet/
                    Beratung in objektorientierter Datenverarbeitung
Ziegelhttenweg 17a, 60598 Frankfurt, Germany Tel. +49(0)179 2607481


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by Gennaro Prot » Thu, 16 May 2002 00:15:12



 >While porting some C++ code from Digital C++ to Microsoft Visual C++ I game
 >across code that looks like this:
 >
 >int x;
 >bool y = x != 0 ? x : throw std::range_error("aaargh...");
 >
 >VC++ gives the following error:
 >
 >error C2440: 'initializing' : cannot convert from 'void' to 'bool'
 >        Expressions of type void cannot be converted to other types
 >
 >Digital C++ compiles it without complaints.
 >Is this valid C++ or a compiler bug in VC++?
 >Is throw an expression that returns a void?

A throw-expression *is* of type void (15/1). Anyhow 5.16p2 explictly
allows your code.

Genny.


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by Ron Natali » Thu, 16 May 2002 00:19:13



> While porting some C++ code from Digital C++ to Microsoft Visual C++ I game
> across code that looks like this:

> int x;
> bool y = x != 0 ? x : throw std::range_error("aaargh...");

> VC++ gives the following error:

> error C2440: 'initializing' : cannot convert from 'void' to 'bool'
>         Expressions of type void cannot be converted to other types

That is correct.

It's not the fact that the throw is illegal, it's that the expressions
to the left and right of the : have to be the same type or one has to
be convertable to the other.  C++ just can't handle an expression
that has undeterminable type at compile time.


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by Ron Natali » Thu, 16 May 2002 00:19:37



> While porting some C++ code from Digital C++ to Microsoft Visual C++ I game
> across code that looks like this:

> int x;
> bool y = x != 0 ? x : throw std::range_error("aaargh...");

I take back what I wrote in my other post.
The above is legal.

The conditional expression has some magic in it for void expressions:

 If either the second or the third operand has type (possibly
 cv-qualified) void, then the lvalue-to-rvalue
 (4.1), array-to-pointer (4.2), and function-to-pointer
 (4.3) standard conversions are performed on the second
  and third operands, and one of the following shall hold:

The second or the third operand (but not both) is a
  throw-expression (15.1); the result is of the type of
  the other and is an rvalue.

The type of the second expression is int.
The type of the throw expression is void.

So the special case applies.  The conditional expression has type
int.


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by Ron Natali » Thu, 16 May 2002 00:19:55



> It is illegal in C++; VC++ is correct (for once).  throw is a statement,
> not an expression.  In a conditional expression, both the true and false
> expressions must have the same type.

Nope, it's legal C++, VC++ is wrong (as usual).

First, throw is NOT a statement.  It is a type of expression
which yields an rvalue of type void.

Second, the second and third operands of the conditional do not
have to be the same type.  They are rules for determining what
combination of types are legal ( so that the overall type of the
expression can be determined).  Essentially, they either have to
be the same type *OR* one is convertable to the other (but not
both).  And a special case exists for expressions yielding void
(see my other post).  A conditional where one side is a throw
and the other is not, is legal and yields an expression of the
type of the other side.


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by Peter van Merker » Thu, 16 May 2002 00:21:42


 > int x;
 > bool y = x != 0 ? x : throw std::range_error("aaargh...");
 >
 > VC++ gives the following error:
 >
 > error C2440: 'initializing' : cannot convert from 'void' to 'bool'
 >         Expressions of type void cannot be converted to other types
 >
 > Digital C++ compiles it without complaints.
 > Is this valid C++ or a compiler bug in VC++?
 > Is throw an expression that returns a void?

throw doesn't return at all, so my guess is that it isn't legal. Even if it
were legal, the code is rather questionable, 'x' is not initialized, and
regardless of the value of 'x', 'y' can only evaluate to 'true'. Besides
that, using 'if' would be IMHO more appropriate way to do it:

if(x == 0)
{
     throw std::range_error("aaargh...");

Quote:}

bool y = x ; // Would always evaluate to true !?

--
Peter van Merkerk
merkerk(at)turnkiek.nl


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by James Kanz » Thu, 16 May 2002 05:37:20



|>  > int x;
|>  > bool y = x != 0 ? x : throw std::range_error("aaargh...");

|>  > VC++ gives the following error:

|>  > error C2440: 'initializing' : cannot convert from 'void' to 'bool'
|>  >         Expressions of type void cannot be converted to other types

|>  > Digital C++ compiles it without complaints.  Is this valid C++
|>  > or a compiler bug in VC++?

|>  It is illegal in C++; VC++ is correct (for once).  throw is a
|>  statement, not an expression.  In a conditional expression, both
|>  the true and false expressions must have the same type.

Not quite.  The rules gouverning the type of a conditional expression
(and its lvalue-ness) are actually quite complex; complex enough that
I have to go to the standard each time myself.  In this case, there is
a very special rule for the case of throw expressions, which says that
the type of the resulting expression is the type of the other
expression (and that at most one of the expressions can be a throw
expression).

Of course, a simple work-around for the bug is:

    bool y = x != 0 ? x : (throw std::range_error("aaargh..."), 0);

This trick will also allow both of the sub-expressions to effectively
be throw expressions:-).

--

Conseils en informatique oriente objet/
                    Beratung in objektorientierter Datenverarbeitung
Ziegelhttenweg 17a, 60598 Frankfurt, Germany Tel. +49(0)179 2607481


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by John Pott » Thu, 16 May 2002 05:44:38



Quote:> While porting some C++ code from Digital C++ to Microsoft Visual C++ I game
> across code that looks like this:

> int x;
> bool y = x != 0 ? x : throw std::range_error("aaargh...");

> VC++ gives the following error:

> error C2440: 'initializing' : cannot convert from 'void' to 'bool'
>         Expressions of type void cannot be converted to other types

As others have stated, it is valid code.  Gcc 2.95 and 3.0.4 also have
this bug which may indicate that it was a late change to the standard
or that it is a detail which is easy to miss.

As a workaround, you might try

   bool y = x != 0 ? x : (throw std::range_error("aaargh..."), 0);

which is accepted by gcc.

If these are automatic variables, the if (x == 0) throw form suggested
does seem to be much cleaner.

John


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by Tonc » Thu, 16 May 2002 05:44:59



> While porting some C++ code from Digital C++ to Microsoft Visual C++ I game
> across code that looks like this:

> int x;
> bool y = x != 0 ? x : throw std::range_error("aaargh...");

> VC++ gives the following error:

> error C2440: 'initializing' : cannot convert from 'void' to 'bool'
>         Expressions of type void cannot be converted to other types

I think VC++ error is true one. ?: is operator, and operator must
return something. In your case x is integer and throw "returns" void.
That's the problem.


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by JKB » Thu, 16 May 2002 05:45:17



> |>  int x;
> |>  bool y = x != 0 ? x : throw std::range_error("aaargh...");
"James Kanze" writes...
> It is valid C++, and there is a bug in VC++ for not accepting it.

Gack.  Throw is an expression, not a statement?  That would make 'throw' an
operator.  But you can't ever take its value, since it throws.  What's its
type - void?  And why?

-- jkb


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by Bing Xi » Thu, 16 May 2002 05:52:30




> |>  While porting some C++ code from Digital C++ to Microsoft Visual
> |>  C++ I game across code that looks like this:

> |>  int x;
> |>  bool y = x != 0 ? x : throw std::range_error("aaargh...");

> |>  VC++ gives the following error:

> |>  error C2440: 'initializing' : cannot convert from 'void' to 'bool'
> |>          Expressions of type void cannot be converted to other types

> |>  Digital C++ compiles it without complaints.
> |>  Is this valid C++ or a compiler bug in VC++?

> It is valid C++, and there is a bug in VC++ for not accepting it.

> |>  Is throw an expression that returns a void?

> Yes.  But there is no place where you attempt to convert this void to
> bool.  What you are attempting to convert to bool is the results of
> the ?: operator.  And according to the standard (5.16/3):

>     If either the second or the third operand has type void, [...],
>     and one of the following shall hold:

>      -- The second or the third operand (but not both) is a
>         throw-expression; the result is of the type of the other, and
>         is an rvalue.

> In this case, the result of ?: is of type int, and you can convert an
> int to a bool.

The following lines should make all compilers happy:

  int x;
  bool y = x != 0 ? x != 0 : (throw std::range_error("aaargh..."), false);


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by Gennaro Prot » Thu, 16 May 2002 16:09:32




[...]

Quote:> In this case, there is
>a very special rule for the case of throw expressions, which says that
> [...] at most one of the expressions can be a throw expression).

Did you misread 5.16p2? Both expression can indeed be throw
expressions (not when you want to assign the result as in the OP code,
of course :) )

Genny.


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Is it legal to throw exceptions from ?: expressions?

Post by Hyman Rose » Thu, 16 May 2002 16:11:35



> at most one of the expressions can be a throw expression

Reread 5.16/2. It's perfectly OK for both of them to be
throw expressions.


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

1. Throwing exceptions in dtors called by thrown exceptions

I've inadvertently ended up with a rather strange case, which my C++
compiler (MSVC++ 6.0 w/SP6) doesn't seem to handle very well.

The actual situation is a bit more complex, of course, but boiled down
it looks like this:

class obj
{
public:
   ~obj()
   {
      throw "obj";
   }

int main()
{
   try
   {
      obj x;
      throw "main";
   }
   catch ( const char * p )
   {
      printf("%s\n", p );
   }

As you can see, in the act of throwing the main exception, the obj x
must be destroyed, which results in throwing another exception. I'm
not sure which one the catch is 'supposed' to catch, but in practice
it doesn't catch either one - the program bombs out completely!

If I comment out the 'obj x;' line, it catches "main" just fine. If I
comment out the 'throw "main";' line, it catches "obj" just fine. But
with both enabled, it doesn't catch either one!

Does anyone know how this is supposed to work? Can anyone try it under
a different compiler? Any ideas on how to make it work?

Thanks...

2. An update for Dr Eliza

3. MSDN says that throwing exception in a constructor causes memory leak in combination with new expression

4. Samba and Solaris

5. Defect Report: Erroneous semantics for new-expression when an exception is thrown

6. 3D Cell libraries of trees and shrubs needed.

7. Defect Report: throw-expression in a constant expression

8. Anybody use the Yamaha CRW4260, 4X write, 2X R/W, 6X Read?

9. C++ Exceptions: throw vs. throw new

10. Exceptions are good...but to throw or not to throw is the problem

11. Exception Objects Throwing Exceptions.

12. Exception while throwing an exception?

13. Is this expression legal.