12

假设 static_cast 永远不会抛出异常是否安全?

对于 Enum 转换的 int,即使它无效也不会抛出异常。我可以依靠这种行为吗?以下代码有效。

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

int y = 10;
animal x = static_cast<animal>(y);
4

4 回答 4

14

对于这种特定类型的强制转换(集成到枚举类型),可能会引发异常。

C++ 标准 5.2.9 静态转换 [expr.static.cast] 第 7 段

整数或枚举类型的值可以显式转换为枚举类型。如果原始值在枚举值 (7.2) 的范围内,则该值不变。否则,生成的枚举值未指定/未定义(C++17 起)。

请注意,由于 C++17 这种转换实际上可能会导致未定义的行为,其中可能包括抛出异常。

换句话说,在static_castC++17 之前,您从整数中获取枚举值的特殊用法一直很好,如果您通过某种输入验证过程确保整数实际上表示有效的枚举值,那么它总是可以的。

有时输入验证过程完全消除了对 a 的需要static_cast,如下所示:

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.
    }
}

请考虑使用类似上述结构的东西,因为它不需要强制转换,并且让您有机会正确处理边界情况。

于 2012-07-18T23:35:48.043 回答
12

假设static_cast永远不会抛出异常是否安全?

不会。对于用户定义的类型,构造函数和/或转换运算符可能会引发异常,从而导致明确定义的行为。

考虑这个程序的输出:

#include <iostream>

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

int main () {
  int y = 7;
  try {
    static_cast<A>(y);
  } catch(...) {
    std::cout << "caught\n";
  }
}
于 2012-07-18T23:58:08.827 回答
7

static_cast不能抛出异常,因为static_cast不是运行时强制转换,如果无法强制转换,代码将无法编译。但是如果它编译并且强制转换是错误的 - 结果是未定义的。

于 2012-07-18T23:30:40.487 回答
3

(此答案专门针对您问题中的int转换enum。)

对于 Enum 转换的 int,即使它无效也不会抛出异常。我可以依靠这种行为吗?以下代码有效。

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

实际上,枚举并不局限于其定义中的枚举列表,这不仅仅是一些奇怪的怪癖,而是枚举的一个特意利用的特性——考虑一下枚举值如何经常被 OR 运算以将它们打包成单个值或 0当没有任何枚举适用时通过。

在 C++03 中,编译器将使用多大的后备整数不受程序员的显式控制,但范围保证跨越 0 和显式列出的枚举。

因此,10 不一定是一个有效的、可存储的值animal。即使支持值不足以存储您尝试转换为的整数值animal,也可以应用缩小转换 - 通常这将使用枚举支持类型可以容纳的许多最低有效位,丢弃任何额外的高阶位,但有关详细信息,请查看标准。

在实践中,PC 和服务器硬件上的大多数现代 C++03 编译器默认使用(32 位)int来支持枚举,因为这有助于调用以 32 位为标准的 C 库函数。

永远不会期望编译器在使用static_cast<>.

于 2012-07-19T00:11:03.600 回答