9

クラス固有のnew_handler実装については、「効果的なc++」という本で次の例に出くわしました。これはマルチスレッド環境では問題に見えます。私の質問は、マルチスレッド環境でクラス固有のnew_handlerを実現する方法です。

void * X::operator new(size_t size)
{
    new_handler globalHandler =                // install X's
    std::set_new_handler(currentHandler);    // handler
    void *memory;
    try {                                      // attempt
        memory = ::operator new(size);           // allocation
    }
    catch (std::bad_alloc&) {                  // restore
        std::set_new_handler(globalHandler);     // handler;
        throw;                                   // propagate
    }                                          // exception
    std::set_new_handler(globalHandler);       // restore
                                               // handler
    return memory;
}
4

3 に答える 3

4

あなたが正しい。これはおそらくスレッドセーフではありません。代わりにのnothrowバージョンをnew使用するなど、別のアプローチを検討することをお勧めします。

void* X::operator new(std::size_t sz) {
  void *p;
  while ((p = ::operator new(sz, std::nothrow) == NULL) {
    X::new_handler();
  }
  return p;
}

これにより、メモリ割り当てが失敗するたびに、クラス固有のハンドラーが呼び出されます。オーバーロードを取り巻く頭痛の種をすべて本当に理解するまで、私はこれをしませんoperator new。特に、Herb Sutter の 2 部構成の記事、To New、Perchance To Throw、Part 1およびPart 2をお読みください。興味深いことに、彼はnothrowバージョンを避けるように言っています...うーん。

于 2009-08-26T02:32:35.227 に答える
0

C ++は(まだ)スレッドが何であるかを知りません。これを行うためのスレッドセーフな方法を決定するために、またはそれが可能であるかどうかを判断するには、コンパイラ/C++標準ライブラリ/オペレーティングシステム/スレッドライブラリのマニュアルを参照する必要があります。新しいハンドラーは、おそらくアプリケーション全体で同じである必要があることをお勧めします。それはあまり柔軟なメカニズムではありません、おそらくあなたのニーズはアロケータまたはおそらく工場(関数)でよりよく満たされるでしょう?カスタムの新しいハンドラー内で何をしたいですか?

于 2009-08-26T02:19:14.110 に答える
0

おそらく、あなたはそれを間違った方法で見ています。アプリケーション全体のメモリ割り当てを制限する方法はないと思います (メモリ割り当ての多くはコード外にある可能性があるため)。ハンドラーの。

プログラムの開始時に「OutOfMemoryHandler」クラスのインスタンスを呼び出すようにハンドラーをセットアップし (好きなように呼び出します)、既存のハンドラーを呼び出すデフォルトの動作を設定します。クラス固有の処理を追加する場合は、動的動作のためのお気に入りの C++ 手法を使用して OutOfMemoryHandler に動作を追加します。

このソリューションは、シングルスレッド環境ではうまく機能しますが、マルチスレッド環境では失敗します。マルチスレッド環境で動作させるには、呼び出し元が特定のスレッドで動作していることをハンドラー オブジェクトに通知する必要があります。これを行うには、クラスでスレッド ID を渡すのが良い方法です。ハンドラーが呼び出されると、スレッド ID がチェックされ、関連するクラスに基づいて実行する動作が決定されます。new() 呼び出しが終了したら、thread-id の登録を解除して、正しいデフォルト動作を保証します (デフォルト ハンドラーのリセットですでに行っているのと同じように)。

于 2009-08-26T03:06:23.660 に答える