Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can static_cast throw an exception in C++?

Tags:

c++

casting

Is it safe to assume that static_cast will never throw an exception?

For an int to Enum cast, an exception is not thrown even if it is invalid. Can I rely on this behavior? This following code works.

enum animal {
  CAT = 1,
  DOG = 2
};

int y = 10;
animal x = static_cast<animal>(y);
like image 539
Hrishi Avatar asked Jul 18 '12 23:07

Hrishi


4 Answers

Is it safe to assume that static_cast will never throw an exception?

No. For user-defined types, the constructor and/or conversion operator might throw an exception, resulting in well-defined behavior.

Consider the output of this program:

#include <iostream>

struct A {
  A(int) { throw 1; }
};

int main () {
  int y = 7;
  try {
    static_cast<A>(y);
  } catch(...) {
    std::cout << "caught\n";
  }
}
like image 121
Robᵩ Avatar answered Oct 17 '22 15:10

Robᵩ


For this particular type of cast (integral to enumeration type), an exception might be thrown.

C++ standard 5.2.9 Static cast [expr.static.cast] paragraph 7

A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the resulting enumeration value is unspecified / undefined (since C++17).

Note that since C++17 such conversion might in fact result in undefined behavior, which may include throwing an exception.

In other words, your particular usage of static_cast to get an enumerated value from an integer is fine until C++17 and always fine, if you make sure that the integer actually represents a valid enumerated value via some kind of input validation procedure.

Sometimes the input validation procedure completely eliminates the need for a static_cast, like so:

animal GetAnimal(int y)
{
    switch(y)
    {
    case 1:
        return CAT;
    case 2:
        return DOG;
    default:
        // Do something about the invalid parameter, like throw an exception,
        // write to a log file, or assert() it.
    }
}

Do consider using something like the above structure, for it requires no casts and gives you the opportunity to handle boundary cases correctly.

like image 22
In silico Avatar answered Oct 17 '22 15:10

In silico


static_cast can't throw exception since static_cast is not runtime cast, if some cannot be casted, code will not compiles. But if it compiles and cast is bad - result is undefined.

like image 7
ForEveR Avatar answered Oct 17 '22 16:10

ForEveR


(This answer focuses exclusively on the int to enum conversion in your question.)

For an int to Enum cast, an exception is not thrown even if it is invalid. Can I rely on this behavior? This following code works.

enum animal {   CAT = 1,   DOG = 2 };
int y = 10; 
animal x = static_cast<animal>(y); 

Actually, enums are not restricted to the list of enumerations in their definition, and that's not just some strange quirk, but a deliberately utilised feature of enums - consider how enumeration values are often ORed together to pack them into a single value, or a 0 is passed when none of the enumerations apply.

In C++03, it's not under explicit programmer control how big a backing integer will be used by the compiler, but the range is guaranteed to span 0 and the explicitly listed enumerations.

So, it's not necessarily true that 10 is not a valid, storable value for an animal. Even if the backing value were not big enough to store the integral value you're trying to convert to animal, a narrowing conversion may be applied - typically this will use however many of the least significant bits that the enum backing type can hold, discarding any additional high order bits, but for details check the Standard.

In practice, most modern C++03 compilers on PC and server hardware default to using a (32 bit) int to back the enumeration, as that facilitates calling into C library functions where 32 bits is the norm.

I would never expect a compiler to throw an exception when any value is shoehorned into an enum using static_cast<>.

like image 3
Tony Delroy Avatar answered Oct 17 '22 14:10

Tony Delroy