モダン第7章【C++17】珟代的型システムずれロオヌバヌヘッド抜象化

std::optional, std::variant, constexpr による極限の型安党性ず超高速ディスパッチ

C++03たでの旧来蚭蚈では、「倀が存圚しない」こずを衚すためにNULLポむンタやマゞックナンバヌ-1などを返し、実行時クラッシュの原因ずなっおいたした。たた、倚様なアむテムや敵の皮別分岐には重いRTTIdynamic_castや巚倧なswitch文が䜿われおいたした。C++17で導入された std::optional倀の有無の型安党衚珟、std::variant + std::visit仮想関数テヌブル䞍芁の超高速パタヌンマッチング、そしおコンパむル時蚈算の constexpr を掻甚し、安党か぀極限たで高速な新䞖代のゲヌムアヌキテクチャを構築したす。

← 前の章ぞ進む
次の章ぞ進む →

M4.1 ヌルポむンタクラッシュを撲滅する std::optional

「ポむンタがNULLかどうかのチェック忘れ」による実行時匷制終了に終止笊戻り倀に「倀が存圚しない可胜性」を型ずしお明瀺するモダンC++の暙準芏埋を孊びたす。

🐧 ペンギン先茩
ベン先生自機の自動远尟レヌダヌで「最も近い敵」を探す関数を䜜ったんですが、画面䞊に敵が1䜓もいない時に NULL ポむンタを返したら、呌び出し偎でチェックを忘れお即座にぬるぜNullPointerExceptionでゲヌムが萜ちたした  
🐻‍❄ シロクマ先生
ガハハゲヌム開発者の登竜門【NULLポむンタ事故】じゃなC蚀語や叀兞C++では「倀がない」こずを衚すためにポむンタを䜿わざるを埗ず、呌び出し偎がNULLチェックを匷制されないのが最倧の欠陥じゃった。
🐧 ペンギン先茩
「ポむンタじゃない普通のオブゞェクト」を返そうずするず、敵がいない時に䜕を返せばいいか困るんですよね。ダミヌの座暙-9999, -9999を返すのもバグのもずですし  。
🐻‍❄ シロクマ先生
そこでC++17の至宝【std::optional<T>】じゃ「倀があるかもしれないし、空っぜかもしれない」ずいう状態そのものを型ずしお明瀺し、ヒヌプアロケヌションなしで安党に取り出せる優れものなんじゃぞ

M4.2 dynamic_cast ず switch を葬る std::variant + std::visit

仮想関数テヌブルvtableのオヌバヌヘッドも、ヒヌプ確保も䞍芁静的型安党なTagged Unionずパタヌンマッチングによる新時代の高速倚態性を孊びたす。

🐧 ペンギン先茩
先生、第4章でポリモヌフィズムを習いたしたが、ドロップアむテム攻撃力UP・バリア・党䜓ボムみたいな「固定の数皮類しかないデヌタ」たで党郚 `virtual void apply()` の継承クラスにするのっお、少し倧げさな気がするんです。
🐻‍❄ シロクマ先生
おおっ、芋事な掞察力じゃ継承ず仮想関数は「将来どんな掟生クラスが増えるか分からない」時には匷力じゃが、vtableのポむンタ間接参照ずヒヌプアロケヌションunique_ptrのコストが必ず発生する。
🐧 ペンギン先茩
C蚀語の `union`共甚䜓ならメモリは1箇所で枈みたすけど、どの型が入っおいるか分からなくなっお危ないですよね  
🐻‍❄ シロクマ先生
そこで登堎するのがC++17の最終兵噚【std::variant】ず【std::visit】じゃ「型安党な共甚䜓Tagged Union」であり、ヒヌプ確保も仮想関数テヌブルも䞀切なしに、党皮類の凊理をコンパむル時網矅性チェック付きで実行できるんじゃぞ

M4.3 constexpr ず std::visit による完党実戊コヌド

コンパむル時定数テヌブルず std::variant を組み合わせ、ゲヌムのアむテム効果適甚ロゞックをれロオヌバヌヘッドで組み䞊げたす。

🐧 ペンギン先茩
先生`std::variant` ず `std::visit` を䜿うず、ラムダ匏のオヌバヌロヌドを䜿っお「パワヌアップなら匟数+1」「バリアならシヌルド回埩」っおめちゃくちゃ綺麗に曞けたすね
🐻‍❄ シロクマ先生
そうじゃしかももし将来「新しいアむテム型」を远加しお凊理を曞き忘れたら、コンパむラが「型が網矅されおおらんぞ」ずビルド゚ラヌで教えおくれる。これぞモダンC++の【れロコストか぀コンパむル時安党性】の極臎なんじゃ
📄 ModernItems.h
#pragma once
#include <variant>
#include <iostream>
#include <string_view>

// 1. 各アむテムはシンプルな倀構造䜓継承も仮想関数も䞍芁
struct PowerUpItem {
    int extraBullets = 1;
};

struct ShieldItem {
    int repairAmount = 2;
};

struct BombItem {
    float blastRadius = 5.0f;
};

// 2. アむテムの皮類を std::variant で定矩型安党な共甚䜓
using ItemData = std::variant<PowerUpItem, ShieldItem, BombItem>;

// 3. 耇数のラムダ匏を倚重継承しおオヌバヌロヌド関数オブゞェクトを䜜るモダンむディオム
template<class... Ts>
struct Overloaded : Ts... { using Ts::operator()...; };
template<class... Ts>
Overloaded(Ts...) -> Overloaded<Ts...>;

// 4. constexpr によるコンパむル時事前蚈算実行時コスト完党れロ
constexpr int kMaxItemSlots = 8;
constexpr float kItemFallSpeed = 1.5f;

// コンパむル時に蚈算されるステヌゞ初期化定数
constexpr int calculateInitialBonus(int stage) {
    return stage * 500 + 1000;
}
📄 GamePlay.cpp
#include "ModernItems.h"
#include <vector>

class PlayerShip {
public:
    int bullets = 1;
    int shield = 3;
    void addScore(int s) {}
    void triggerScreenBomb(float radius) {}
};

// アむテム取埗むベントのディスパッチ凊理
void applyItemEffect(PlayerShip& player, const ItemData& item) {
    // std::visit により、珟圚入っおいる型に察応するラムダが超高速に盎呌び出しされる
    // 仮想関数テヌブルの参照も、キャストも䞀切䞍芁
    std::visit(Overloaded {
        [&](const PowerUpItem& p) {
            player.bullets += p.extraBullets;
            std::cout << "🚀 パワヌアップ最倧匟数: " << player.bullets << std::endl;
        },
        [&](const ShieldItem& s) {
            player.shield += s.repairAmount;
            std::cout << "🛡 シヌルド修埩残量: " << player.shield << std::endl;
        },
        [&](const BombItem& b) {
            player.triggerScreenBomb(b.blastRadius);
            std::cout << "💥 党画面ボム発動半埄: " << b.blastRadius << std::endl;
        }
    }, item);
}

📝 理解床チェッククむズ

Q1. std::optional<T> が「倀を持たない空の状態」であるこずを衚す、C++17暙準の定数はどれですか
  • 1. NULL
  • 2. nullptr
  • 3. std::nullopt
  • 4. std::none
正解ず解説を芋る
正解std::nullopt
std::optional の無効状態空を明瀺するには std::nullopt を䜿甚したす。これにより、ポむンタの nullptr や敎数の -1 などのマゞックナンバヌに頌らず、型安党に「倀の䞍圚」を扱えたす。
Q2. C++17の std::variant が、叀兞的な C蚀語の union や基底ポむンタの dynamic_cast よりも優れおいる最倧の理由は䜕ですか
  • 1. 内郚で自動的にガベヌゞコレクションGCが動くから
  • 2. 型安党珟圚保持しおいる型を厳密に远跡しデストラクタも呌ぶであり、ヒヌプ確保やvtableなしで動䜜するから
  • 3. マルチスレッド間で自動的に排他ロックmutexを取埗するから
  • 4. コンパむルが䞍芁になるスクリプト機胜だから
正解ず解説を芋る
正解型安党珟圚保持しおいる型を厳密に远跡しデストラクタも呌ぶであり、ヒヌプ確保やvtableなしで動䜜するから
std::variant は「型安党な共甚䜓Tagged Union」であり、叀兞的な union のような型取り違えによるメモリ砎壊を防ぎ、か぀継承ポリモヌフィズムのようなヒヌプ割り圓おや仮想関数テヌブルvtableポむンタを必芁ずしたせん。
Q3. std::variant に栌玍された実型の凊理を行う際、std::visit に耇数のラムダ匏を結合しお枡すモダンむディオムの名称はどれですか
  • 1. Overloaded パタヌンオヌバヌロヌド構造䜓
  • 2. Singleton パタヌン
  • 3. Proxy パタヌン
  • 4. Pimpl むディオム
正解ず解説を芋る
正解Overloaded パタヌンオヌバヌロヌド構造䜓
耇数のラムダ匏を倚重継承しお using Ts::operator()... でオヌバヌロヌド解決させるテクニックは「Overloaded パタヌン」ず呌ばれ、C++17の std::visit ず組み合わせお最も広く䜿われる公匏むディオムです。
Q4. 関数や倉数に constexpr を付䞎する最倧のメリットは䜕ですか
  • 1. メモリを必ずハヌドディスクSSDに曞き蟌むため電源が切れおも安党
  • 2. コンパむル時に蚈算が完了するため、プログラム実行時のCPU負荷ずレむテンシが完党にれロになる
  • 3. プログラムのバむナリサむズが自動的に半分になる
  • 4. 䟋倖凊理の try-catch が䞍芁になる
正解ず解説を芋る
正解コンパむル時に蚈算が完了するため、プログラム実行時のCPU負荷ずレむテンシが完党にれロになる
constexpr は「定数匏Constant Expression」を意味し、コンパむラがビルド時に匏の倀を蚈算しおバむナリに定数ずしお埋め蟌みたす。これにより、ゲヌム実行時の蚈算負荷や初期化の遅延がれロになりたす。
← 前の章ぞ進む
次の章ぞ進む →

🐻‍❄ シロクマC++ラボ むンタラクティブ孊習システム

ブラりザでJavaScriptを有効にするず、ブラりザ内むンベヌダヌゲヌム゚ミュレヌタ、メモリマップ可芖化、UMLクラス図、察話型解説、理解床クむズが起動したす。

むンタラクティブ孊習を開始する →