2

allegro オープン ソース ライブラリを使用したシンプルなタンク ウォーズ スタイルのゲームがあります。私のタンク クラスでは、ビットマップ オブジェクトへのポインターの配列を 0 に初期化します。次に、メモリを割り当てて初期化する allegro 関数 create_bitmap を使用して新しいオブジェクトを作成します。

それから私はいつものように私の仕事に取り掛かります。

問題は、善良な OO 少年のようにクラス デストラクタでビットマップ メモリを解放しようとすると、プログラムがクラッシュすることです。これは、この特定のプログラムでは、allegro ライブラリがクラスの前にクリーンアップ (作成したビットマップ オブジェクトを解放する) を行うためです。範囲外になり、破壊されます。ただし、ポインタが再度 NULL に設定されるわけではないため、ビットマップがまだ有効かどうかを確認できず、解放しようとするとプログラムがクラッシュします。

これを回避する方法はありますか?NULL でない場合、有効なポインターをチェックできますか? クラスがプログラム内で別の方法で使用されている場合、メモリが解放されていることを確認するにはどうすればよいですか。現在のところ、私は基本的に削除せずに new を呼び出していますが、それは好きではありません。

4

9 に答える 9

5

問題は、アレグロがビットマップ自体を解放することではなく (または、終了時にビットマップを解放する必要がないこと)、デストラクタが呼び出される前にアレグロ ライブラリが初期化解除されていることだと思います。

int main()
{
    ObjectManagingBitmaps o;
    ...
    return 0;
    //allegro automatically shut down here
} //o destructor invoked here
END_OF_MAIN()

デストラクタが最初に呼び出されるようにするためにできることは、人為的なスコープを使用することです。

int main()
{
    {
    ObjectManagingBitmaps o;
    ...
    } //o destructor invoked here
    return 0;
    //allegro automatically shut down here
} 
END_OF_MAIN()
于 2009-11-02T23:10:36.053 に答える
3

生のポインターの配列を使用しないでください。Allegro には acreate_bitmapと adestroy_bitmap関数が付属しています。これは、コンストラクターとデストラクターの C++ の概念に非常にうまく対応しています。AllegroPlusPlus::bitmap正確に 1 つのビットマップを管理するクラスが必要です。Tank クラスは単純にそれらの配列を持つことができます。

これが責任の分離です。タンク クラスは、ビットマップとそのメモリ管理についてあまり詳しくなく、ビットマップ クラスは正確に 1 つのビットマップを処理する必要があります。

Tank クラスでビットマップをリサイクルしたいとします。これは問題ありません。bitmap::operator=(bitmap const&)または他のオーバーロードを適切に実装することで簡単に実行できます。ただし、その割り当ては、タンク クラスではなく、ビットマップ クラスの責任にします。

于 2009-11-02T15:53:42.650 に答える
2

NULL でない場合、有効なポインターをチェックできますか?

いいえ、しかし、あなたの場合は必要ありません。Allegro はそのリソースを処理することを約束しているため、Allegro リソースのリソース処理に干渉する必要はありません (また干渉してはなりません)。特に、リソースがどのように割り当てられているかさえわからないため、リソースの割り当てを解除することはできません

于 2009-11-02T15:04:23.717 に答える
1

かなり恐ろしい漏れのある抽象化のように聞こえます

メモリがどのように割り当てられているかを正確に知らなければ、メモリを破壊する安全な方法を見つけることは期待できません。クリーンアップ機能は、理由があって仕事をしているように聞こえます-それと一緒に暮らす必要があります。

もちろん、他の開発者が同じ罠に陥らないように、これらのビットをラップしてコメントにドキュメントを含めることもできます。

また、アプリケーションのプロファイルを作成して、リークがないことを確認してください。

于 2009-11-02T15:09:23.193 に答える
1

デストラクタはいつ呼び出されますか? Allegro ライブラリがシャットダウンされた後ですか? もしそうなら、最初にすべてのオブジェクトを削除できますか?

于 2009-11-02T19:53:15.197 に答える
1

メモリを明示的に管理するための鍵は、一度に同じメモリ領域への複数のポインタを持つことができますが、指定された所有者はそのうちの 1 つだけであり、他のすべてはそれを共有するだけであるということです。ヒープ オブジェクトが他のヒープ オブジェクトを所有している場合、それらはツリーを構成し、グローバルまたはローカル スコープの変数をルートとします。

最初の Allegro 呼び出しから戻ると、Allegro は渡すメモリ領域の所有者であり、独自のポインターは単に共有ポインターであると見なす必要があります。

いいえ、アロケーターの策略を除けば、メモリが有効かどうかを判断する標準的な方法はありません。アロケータの策略はデバッグ目的には役立ちますが、ライブラリの内部をいじらないでください。

于 2009-11-02T15:08:14.257 に答える
0

ヒープ メモリへの複数のポインターを処理する場合は、参照カウントを使用します。基本的に、同じメモリへの複数の参照があり、1 つを削除した場合、他の参照はまだ存在していると見なす可能性があります。

http://en.wikipedia.org/wiki/Reference_counting

于 2009-11-02T22:21:54.533 に答える
0

これを正しく使用していますか?古い Allegro コードの一部を掘り出し、create_bitmap 呼び出しを伴うコンストラクターと release_bitmap 呼び出しを伴うデストラクタを用意しましたが、問題なく動作しました。

Allegro がメモリを自動的に解放したことについては何も覚えていません。ポインタをメモリ以外の値で誤って上書きしていませんか? このポインターが解放されている別の場所はありますか?

于 2009-11-02T15:31:51.937 に答える
0

Allegro をシャットダウンする前に、オブジェクトがすべて破棄されていることを確認する必要があると思います。これは、Allegro をシャットダウンする前にオブジェクトが存在するスコープを閉じることで簡単に行うことができます (オブジェクトがスタックにある場合)。

これより前に Allegro をシャットダウンする必要がある場合 (たとえば、致命的なエラーのため)、exit を呼び出すことができます。この場合、デストラクタは実行されません (ただし、プログラムはクラッシュしません)。

プログラムが終了時にクリーンアップされることを確認するのにあまり時間をかけないでください。実行中にリークしないようにするための労力を節約してください:)

于 2009-11-13T22:54:49.533 に答える