【C++】インスタンス化の罠

eye-catch C/C++
eye-catch

なんとしても見つけ出したい信念に駆られ…


正常系のテストでは発生しない事例であるため、無視しようかどうしようかギリギリまで迷っておりましたが、やはり気が付けば追求を始めてました。

sprite_bank_ = new sprites::SpriteBank;
if (!sprite_bank_->Load("ROCKMAN", "assets/graphic_material/sprites_tile/rockman/r2t_trsp.png", 400, 20, 20, 32, 32)) {
    refs = eBeacon::HI_EMERGENCY;
    log_context_.append("Can't ").append("ROCKMAN").append(" loading for ").append("assets/graphic_material/sprites_tile/rockman/r2t_trsp.png");
}
if (!sprite_bank_->Load("METALL", "assets/graphic_material/sprites_tile/enemy1/e1001_metall_ex_set.png", 16, 4, 4, 32, 32)) {
    refs = eBeacon::HI_EMERGENCY;
    log_context_.append("Can't ").append("METALL").append(" loading for ").append("assets/graphic_material/sprites_tile/enemy1/e1001_metall_ex_set.png");
}

上記Loadでスプライトデータ(グラフィック)をLoad(メモリに読み込み)します。

メモリに読み込まれたデータはDrawなどで画面に描画して使います。

inline bool GraphicBank::Load(std::string labels, std::string files, int all_num, int x_num, int y_num, int x_size, int y_size) {
    // Is the Factory Method pattern. The instance is machined and generated in the casting class.
    IGadgets* product = factory->createDiv(files, all_num, x_num, y_num, x_size, y_size);
    if (nullptr == product) return false;
    handles_.push_back(product);
    label_.push_back(labels);
    return true;
}

ちょっとデザインパターン使ってますが、createDivメソッドでグラフィックアセットのファイルパスを渡して、それ以外の引数情報を元にどんなサイズで、何個に分割するかを指定しています。

IGadgets* GadgetDiecast::createDiv(std::string filepath, int all_num, int x_num, int y_num, int x_size, int y_size) {
    IGadgets *gadget = createDivineGadget(filepath, all_num, x_num, y_num, x_size, y_size);
    return gadget;
}
IGadgets* GraphicGadget::createDivineGadget(std::string filepath, int AllNum, int XNum, int YNum, int XSize, int YSize) {
    SpriteObject *sprite = new SpriteObject(filepath);
    if (-1 == sprite->getOwner()) return nullptr;
    sprite->Divine(AllNum, XNum, YNum, XSize, YSize);
    return sprite;
}
SpriteObject::SpriteObject(std::string filepath) {
    GrHandle = LoadGraph(filepath.c_str());
    vGrHandle.clear();
}

void SpriteObject::Divine(int allnum, int xnum, int ynum, int xsize, int ysize) {
    int count = 0;
    for (int y = 0; y < ynum; y++) {
        for (int x = 0; x < xnum; x++) {
            if (allnum < count) return;
            vGrHandle.push_back(DerivationGraph(x * xsize, y * ysize, xsize, ysize, GrHandle));
            count++;
        }
    }
}

最終的にDXライブラリのLoadGraph関数でグラフィックデータをメモリロードしてると考えてもらえればいいです。

問題はそこではなく、以下をご覧ください。

IGadgets* GraphicGadget::createDivineGadget(std::string filepath, int AllNum, int XNum, int YNum, int XSize, int YSize) {
    SpriteObject *sprite = new SpriteObject(filepath);
    if (-1 == sprite->getOwner()) return nullptr;  // Cannot load a graphic file.
    sprite->Divine(AllNum, XNum, YNum, XSize, YSize);
    return sprite;
}

これだけ見ると「これは何ですか?」状態なのですが、実はこれダメです
何がダメなんだ?と。

私も分かりませんでした。

sprite->getOwner() は new SpriteObject(ファイルパス) でメモリに読み込まれたグラフィックのシリアル値(DXライブラリ定義)を取得するのですが、-1だったらメモリに配置できてない状態を意味しています。
つまりグラフィックロードの失敗。

その時に return で処理を抜けています。

空メモリに対してグラフィックの加工をしてしまうと壊れますからねヽ(^o^)丿

ですが、return をする前に、すぐ手前で new をしており、これの後始末をしていません。

それに気が付いたあなた!

師匠と呼ばせてください・・・🥺

コメント

タイトルとURLをコピーしました