2 / 4 画像ハンドルの所有権とRAIIパターン
リソース管理の中心となる所有権とRAIIを理解し、メモリリークと二重解放を防ぐ仕組みを学びます。
画像ハンドルをManagerが一元所有する
DXライブラリのLoadGraph()が返すグラフィックハンドル(整数値)は、DirectXやOSのVRAM上に確保されたテクスチャリソースを指し示す識別番号です。
ImageManagerは、これらのハンドルを内部の配列handlesに格納して一元所有します。
private:
// 各画像IDに対応するDXライブラリのグラフィックハンドル(未読み込み時は -1)
std::array<int, static_cast<std::size_t>(Id::Count)> handles = {};自機や敵のクラスは、ハンドルを持ちません。そのため、自機が撃破されたときや敵が全滅したときに、画像を解放してよいかを判断する必要はありません。キャラクターの出現・消滅と、画像を保持する期間を分けて管理します。
RAII(デストラクタによる自動解放)の実装
確保したメモリ、ファイル、DirectXのテクスチャなどは、使い終わったら解放します。ゲーム終了時にRelease()を呼ぶだけでは、途中のエラー終了や呼び忘れで解放漏れが起きます。
C++では、オブジェクトの構築時にリソースを確保し、破棄時にデストラクタで自動解放する方法が広く使われています。この方法をRAII(Resource Acquisition Is Initialization)と呼びます。
ImageManager::ImageManager()
{
// 初期状態はすべて「未取得」を表す -1 で埋める
handles.fill(-1);
}
ImageManager::~ImageManager()
{
// デストラクタ:ImageManager が破棄される際に自動的に実行される
for (int handle : handles)
{
// 正常に取得されているハンドルのみを解放する
if (handle != -1)
DeleteGraph(handle);
}
}ImageManagerのインスタンスが破棄されると、デストラクタが取得済みのハンドルを解放します。呼び出し側は、同じハンドルを重ねて解放しないようにします。
コピー禁止による二重解放(Double Free)の防止
リソースを所有するクラスでは、コピーを禁止する点を確認します。
public:
// コピーコンストラクタとコピー代入演算子を明示的に削除(禁止)する
ImageManager(const ImageManager&) = delete;
ImageManager& operator=(const ImageManager&) = delete;ImageManagerをコピーすると、同じハンドルを持つManagerが2つできます。たとえば、両方がハンドル番号10を持つ状態になります。
両方が破棄されると、同じハンドル10に対してDeleteGraph()を2回実行してしまいます。これが二重解放(Double Free)です。DirectXのエラーや突然のクラッシュにつながる危険なバグです。
= deleteでコピーを禁止すると、誤ったコピーをコンパイル時に検出して防げます。
- 画像ハンドルの所有権が
ImageManagerに集約されている理由を説明できる - RAIIパターンの概念と、デストラクタで自動解放する利点を理解している
- 読み込みに失敗した(
-1の)ハンドルを誤って解放しないようガードされている - リソース所有クラスでコピーコンストラクタを削除(
= delete)する理由を説明できる