Может ли static_cast вызывать исключение в С++?

Можно ли предположить, что static_cast никогда не будет генерировать исключение?

Для int для перечисления Enum исключение не выбрасывается, даже если оно недействительно. Могу ли я полагаться на это поведение? Этот следующий код работает.

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

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

Ответ 1

Для данного конкретного типа (целочисленного типа перечисления) может быть выбрано исключение.

Стандарт С++ 5.2.9 Статический литье [expr.static.cast] пункт 7

Значение интегрального или перечисляемого типа может быть явно преобразовано в тип перечисления. Значение не изменяется, если исходное значение равно в пределах диапазона значений перечисления (7.2). В противном случае итоговое значение перечисления не указано /undefined (поскольку С++ 17).

Обратите внимание, что поскольку С++ 17 такое преобразование может фактически привести к поведению undefined, которое может включать в себя исключение исключения.

Другими словами, ваше конкретное использование static_cast для получения перечисляемого значения из целого числа является прекрасным до С++ 17 и всегда прекрасным, если вы убедитесь, что целое число действительно представляет допустимое числовое значение через какой-либо тип процедура проверки ввода.

Иногда процедура проверки ввода полностью устраняет необходимость в 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.
    }
}

Подумайте о том, чтобы использовать что-то вроде вышеуказанной структуры, поскольку оно не требует отбросов и дает вам возможность правильно обрабатывать граничные случаи.

Ответ 2

Можно ли предположить, что 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";
  }
}

Ответ 3

static_cast не может генерировать исключение, поскольку static_cast не выполняется при запуске, если некоторые из них не могут быть выполнены, код не будет компилироваться. Но если он компилируется и отличен, результат - undefined.

Ответ 4

(Этот ответ фокусируется исключительно на преобразовании int to enum в вашем вопросе.)

Для int для перечисления Enum исключение не выбрасывается, даже если оно недействительно. Могу ли я полагаться на это поведение? Этот следующий код работает.

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

Фактически, перечисления не ограничены списком перечислений в их определении и что не только какая-то странная причуда, но и намеренно используемая особенность перечислений - рассмотрите, как значения перечисления часто ORed вместе, чтобы упаковать их в одно значение, или 0, когда ни одна из перечислений не применяется.

В С++ 03 он не под явным программистом управляет тем, как большой компилятор будет использовать целочисленное целое, но диапазон гарантированно будет охватывать 0 и явно перечисленные перечисления.

Таким образом, не обязательно верно, что 10 не является допустимым, сохраняемым значением для animal. Даже если значение поддержки не было достаточно большим для хранения интегрального значения, которое вы пытаетесь преобразовать в animal, может применяться сужающее преобразование - обычно это будет использовать, однако, многие наименее значимые биты, которые может поддерживать тип поддержки перечисления, отбрасывая любые дополнительные биты высокого порядка, но для подробностей проверяйте Стандарт.

На практике большинство современных компиляторов С++ 03 на ПК и серверном оборудовании по умолчанию используют (32 бит) int для возврата перечисления, поскольку это облегчает вызов в библиотечные функции C, где 32 бита являются нормой.

Я бы никогда не ожидал, что компилятор будет генерировать исключение, когда любое значение будет перекодировано в enum с помощью static_cast<>.