static_cast が例外をスローしないと仮定しても安全ですか?
int から Enum へのキャストの場合、無効であっても例外はスローされません。この動作に依存できますか? この次のコードは機能します。
enum animal {
CAT = 1,
DOG = 2
};
int y = 10;
animal x = static_cast<animal>(y);
この特定のタイプのキャスト (列挙型に統合)では、例外がスローされる場合があります。
C++ 標準 5.2.9 静的キャスト [expr.static.cast] パラグラフ 7
整数型または列挙型の値は、明示的に列挙型に変換できます。元の値が列挙値 (7.2) の範囲内にある場合、値は変更されません。それ以外の場合、結果の列挙値は未指定/未定義です (C++17以上)。
C++17以降、このような変換は実際には未定義の動作を引き起こす可能性があり、例外のスローが含まれる可能性があることに注意してください。
言い換えれば、static_cast
整数から列挙値を取得するための特定の使用法は、C++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.
}
}
上記の構造のようなものを使用することを検討してください。キャストを必要とせず、境界ケースを正しく処理する機会が得られるからです。
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";
}
}
static_cast
ランタイム キャストではないため、例外をスローできませんstatic_cast
。キャストできないものがあると、コードはコンパイルされません。しかし、コンパイルしてキャストが悪い場合、結果は未定義です。
int
(この回答は、質問のtoenum
変換のみに焦点を当てています。)
int から Enum へのキャストの場合、無効であっても例外はスローされません。この動作に依存できますか? この次のコードは機能します。
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<>
。