品質のための道具 — 静的解析・サニタイザ・警告レベル・CI¶
バグを「実行して踏む」前に機械に見つけさせる4つの層です。検出が早いほど安い(コンパイル時 < テスト実行時 < QA < ユーザー環境)という原則で並べます。
1. 警告レベル(コンパイル時・無料)¶
コンパイラの警告は「合法だが怪しいコード」の検出器です。
GCC/Clang: -Wall -Wextra # 「Wallで全部」ではない点に注意(歴史的な名前)
-Wconversion(縮小変換) -Wshadow(変数の隠蔽)などを追加
MSVC: /W4 # /Wallはシステムヘッダーまで鳴るので/W4が実用上限
共通: -Werror | /WX # 警告をエラー化(CIでは必須級)
- 検出例: 未初期化の可能性、符号比較、到達しないコード、enum switchの網羅漏れ(→ enum)、UBの前兆多数
- プロジェクト開始時に最大化して-Werrorが鉄則。途中から上げると数千件のノイズで詰む。サードパーティのヘッダーは警告抑制の対象外にする(SYSTEMインクルード扱い)
2. 静的解析(コンパイル時+α)¶
コードを実行せず、データフロー・パス解析でバグを探すツール。警告より深い(関数間・パス依存の解析)。
- clang-tidy: 定番。バグ検出+モダン化提案(「生ループをrange-forに」等)+命名規則。CMakeと統合可能
- MSVCの
/analyze、PVS-Studio(ゲーム業界で採用例が多い商用)、Cppcheck - 検出例: nullチェック漏れのパス、リークするパス、危険なキャスト、コピーの見落とし
- 誤検出(false positive)とは付き合い方が必要: 抑制コメントを乱発せず、ルールセットをプロジェクトに合わせて絞る
3. サニタイザ(実行時・開発ビルドの標準装備)¶
コンパイラがチェックコードを織り込み、実行中にUB・メモリバグを捕まえる仕組み(→ メモリバグ図鑑との対応)。
| サニタイザ | 捕まえるもの | 速度低下(目安) |
|---|---|---|
| ASan (Address) | 範囲外・UAF・double free・リーク | ~2倍 |
| UBSan (UndefinedBehavior) | 符号オーバーフロー、null参照外し、不正シフト等 | 軽微 |
| TSan (Thread) | データ競合(→ 並行バグ) | 5〜15倍 |
| MSan (Memory) | 未初期化読み取り(Clang/Linux限定) | 3倍 |
g++ -fsanitize=address,undefined -g -O1 game.cpp # ASan+UBSan併用が開発の定番
MSVC: /fsanitize=address(VS2019 16.9+)
- 「たまに落ちる」を数週間追う vs ASanで一発——費用対効果はC++ツールで最大級。開発ビルドとCIテストに常設する
- 制約: Shippingには入れない(速度・メモリ)。プラットフォームにより対応差(本Wikiの検証環境MinGW GCC 9.2は非対応のため、記述はGCC/Clang/MSVCの公式ドキュメント準拠)
4. CI (Continuous Integration)¶
push/PRのたびに機械がビルド+テスト+解析を回す仕組み(GitHub Actions、Jenkins等)。
ゲームC++プロジェクトの典型パイプライン:
push → [ビルド: MSVC + Clang 両方 / Debug + Shipping 両方] ← 構成差・処理系差の早期検出
→ [ユニットテスト(ASan/UBSan付き)]
→ [clang-tidy / フォーマットチェック]
→ [(夜間)フルアセットビルド + 自動プレイテスト + TSan]
- 「自分のマシンでは通る」を殲滅するのが役割。ビルドを壊した変更を10分で検出できれば、修正コストは最小で済む
- ゲーム特有: アセットビルドの検証、実機スモークテスト(起動して1分遊ぶbot)、性能リグレッション検出(フレーム時間の統計)
C#/Unityとの対応¶
| C#/Unity | C++ |
|---|---|
| コンパイラ警告+Roslyn Analyzer | 警告+clang-tidy等 |
| (言語仕様で大半のUBが例外化) | サニタイザで後付け検出 |
| Unity Test Framework + Cloud Build | ユニットテスト+CI |
C#は言語がチェックを内蔵しているぶん道具が少なくて済んでいました。C++はチェックをツールで外付けする文化——道具を入れないC++開発は、シートベルトなしの運転に近い、という感覚を持つのが正解です。
実務指針(導入順)¶
- 警告最大化+Werror(初日)
- CIで2コンパイラ×2構成ビルド(最初の週)
- テストにASan/UBSan(テストを書き始めたら即)
- clang-tidy(ルールを絞って段階導入)
- TSan・自動プレイテスト(並行コード・規模が出てきたら)
理解度チェック¶
- 「検出が早いほど安い」の4段階を言えますか。
- ASanが劇的に有効なバグの種類は?(第7部のバグ図鑑と対応させて)
- CIで「2コンパイラ×2構成」を回す理由は?
演習¶
samples/ の任意のサンプルに意図的な範囲外アクセスを仕込み、(a) 警告で捕まるか、(b) 手元の環境でASanが使えるなら検出メッセージ(確保・解放・使用の3スタックトレース)を観察してください。使えない環境では、MSVCの/RTCやat()での代替検出を試してください。