Appearance
第24回 地形の種類追加と作品の完成コンパイル時の件数検証(
なぜ
2 / 4 リソース登録の不足と重複を検出する
このステップの目的
コンパイル時の静的アサーション(static_assert)と起動時の動的バリデーションを組み合わせ、リソースの登録漏れ・ID重複・空パスなどの設定ミスを確実に検出する仕組みを実装します。
コンパイル時の件数検証(static_assert)
リソース定義テーブルにおいて、起きやすいミスの1つが「列挙型に新しい項目を追加したのに、定義配列への行追加を忘れてしまうこと」です。
これを未然に防ぐため、コンパイル時に配列の要素数と列挙型の総数(Count)が一致しているかを static_assert で検証します。
cpp
constexpr std::size_t ImageIdCount = static_cast<std::size_t>(ImageId::Count);
constexpr std::size_t ImageDefinitionCount = sizeof(imageDefinitions) / sizeof(imageDefinitions[0]);
static_assert(ImageDefinitionCount == ImageIdCount,
"ImageIdの総数とimageDefinitionsの要素数が一致していません。");もし登録漏れがあればコンパイル時にエラーとなり、問題のあるコードが実行バイナリとして出力されるのを防ぎます。
なぜ static_assert だけでは不十分なのか
static_assert による検証は「配列の総件数」のみを比較しています。そのため、以下のようなミスが発生した場合には検出できません:
- 既存の定義行をコピー&ペーストして、IDの変更を忘れた(同じIDが2回登録され、別のIDが1つ欠落している)
- 配列の件数は合っているが、ファイルパスが空文字列(
"")になっている
この場合、総件数は Count と一致してしまうため、コンパイル時アサーションをすり抜けてしまいます。
起動時の重複・欠落・妥当性検証
コンパイル時の検査をすり抜けた論理的欠陥を検出するため、マネージャの読み込み初期化処理(LoadAll)の冒頭で実行時バリデーションを実施します。
cpp
bool HasCompleteImageDefinitions()
{
std::array<bool, ImageIdCount> registered = {};
for (const ImageDefinition& definition : imageDefinitions)
{
const std::size_t index = static_cast<std::size_t>(definition.id);
// 1. 範囲外のIDや重複登録の検出
if (index >= ImageIdCount || registered[index])
return false;
// 2. 空パスの検出
if (definition.path == nullptr || definition.path[0] == L'\0')
return false;
registered[index] = true;
}
// 3. すべてのIDが漏れなく登録されているか確認
for (bool isRegistered : registered)
{
if (!isRegistered)
return false;
}
return true;
}音声定義(SoundManager)においても同様のチェックに加え、DXライブラリの音量規定値(0 <= volume <= 255)を満たしているかを検証します。
素材ファイルの読み込み処理(LoadGraph など)に入る前に定義テーブル自体の整合性を確認することで、「アセットファイルが壊れているのか、プログラム側の登録表が間違っているのか」を明確に切り分けることができます。
チェックリスト
-
static_assertを用いて列挙型の総数と配列要素数の不一致をコンパイル時に検出できる - 件数比較だけでは検出できない「IDの重複登録」や「空パス」の危険性を説明できる
- 起動時バリデーションによってリソース定義の欠落や不正な値を確実に検出し、原因切り分けを容易にできる