1

私は単純なメモリ アリーナ アロケーターを作成していて、例外の安全性に関する小さな問題に直面しています。状況は、それ自体がアロケーターを呼び出すオブジェクトを割り当てる場合です。メモリ プールの目的は、一度に多数のオブジェクトを割り当て、プールが破棄されたときにそれらをすべて削除することです。

{
    MemoryArena m;
    std::string* ptr = m.Allocate<std::string>();
    // use ptr whatever
    // Cleaned up when pool is destroyed
}

しかし、これは複数回使用するとかなり厄介になります。内部割り当てがクリーンアップされた場合、後で使用できます。プールの定義は、有効期間が終了するまでオブジェクトを削除しないため、悪い仮定ではありません。検討:

struct X {
    X(MemoryArena* ptr, std::string*& ref) {
        ref = ptr->Allocate<std::string>();
        throw std::runtime_error("hai");
    }
};
MemoryArena m;
std::string* ptr;
m.Allocate<X>(&m, ptr);
// ptr is invalid- even though it came from the arena 
// which hasn't yet been destroyed

しかし、内側の割り当てクリーンアップされない場合、外側の割り当てもクリーンアップできません。これは、メモリ アリーナがハードウェア スタックのように線形に割り当てるため、メモリ リークが発生するためです。したがって、オブジェクトを早期に破棄してセマンティクスに違反するか、メモリ リークを起こします。

この問題を解決する方法について何か提案はありますか?

4

2 に答える 2

2

これが適用されるのは単なるサンプルコードかもしれませんが、スローptrのコンストラクターが有効であるとユーザーが想定すべきではないと思います。Xref が割り当てられる前にスローされた可能性もあります。

したがって、可能であれば内側のオブジェクトをクリーンアップすることをお勧めします (つまり、アリーナの正面が現在内側のオブジェクトの最後にある場合)。OK、アリーナからの割り当ては無効になります。これは正常ではありませんが、とにかく現実世界に出てはならない割り当てです.

おそらく、「ソフト」割り当ての概念を使用して、これを明示的にすることができます。まだ「ソフト」である間はアリーナに解放される可能性があるため、永遠に存続することは保証されていません。次に、X のコンストラクターは次のようになります。

SoftPtr<std::string> tmp(ptr->SoftAllocate<std::string>());
stuff_that_might_throw(); 
ref = tmp.release();

SoftPtr最初の呼び出しなしでのデストラクタの実行はrelease、オブジェクトへの参照が公開されていないことを意味します。次のような処理を行う MemoryArena の関数を呼び出します。

  • オブジェクトを破壊する
  • これがアリーナからの最新の割り当てかどうかを確認します
    • その場合、アリーナの現在の位置ポインタからサイズを引きます
    • そうでない場合は、他に何もしません (メモリがリークされます)。

そのため、逆の順序で行われれば、任意の数の割り当てを「バックアウト」できます。

于 2011-12-21T18:16:22.267 に答える
0

メモリプールのセマンティクスそのものにより、質問で述べたように、個々のオブジェクトではなく、プール全体のみを解放できます。それでも、あなたはまさにそれをしたいのです。

次の割り当てアドレスを取得および設定するために、アロケータにbrk のような関数を装備することが可能です。これにより、その上に必要なものを構築するために使用できる低レベルのメカニズムが提供されます。

于 2011-12-21T18:34:15.473 に答える