2009-08-26 15 views
9

クラス固有のnew_handlerの実装については、book "effective C++"の次の例を参照しました。これはマルチスレッド環境で問題に見えますが、私の質問はマルチスレッド環境でクラス固有のnew_handlerを達成する方法ですか?クラス固有のset_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

あなたはそうです。おそらくスレッドセーフではありません。代わりにnothrow version of 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をオーバーロードしているすべての頭痛を本当に理解するまで、私はこれをしません。特に、ハーブ・サッターの2部の記事を投げ捨てるために、Part 1Part 2と読んでください。面白いことに、彼はnothrowバージョン... hmmmを避けるように言います。

0

C++はスレッドが何であるかを(まだ)知りません。これを行うためのスレッドセーフな方法を決定するために、あるいは可能であれば、コンパイラ/ C++の標準ライブラリ/オペレーティングシステム/スレッドライブラリのマニュアルを参照する必要があります。私は、新しいハンドラがおそらくアプリケーション全体で同じであるべきであることを示唆しています。それは非常に柔軟なメカニズムではないでしょう。おそらく、あなたのニーズはアロケータかファクトリ(ファンクション)でうまくいくでしょうか?カスタムハンドラの中で何をしたいのですか?

0

おそらくあなたは間違った方法を見ているでしょう。私は、メモリ全体の割り当てがアプリケーションのメモリの割り当て外になる可能性があるため、アプリケーション全体を制限する方法はないと思っています。そのためには、できることを制御することが最善の方法です。ハンドラの

ハンドラをセットアップして、プログラムの開始時に "OutOfMemoryHandler"クラスのインスタンスを呼び出す(これを呼び出す)と、既定の動作で既存のハンドラを呼び出すように設定します。クラス固有の処理を追加する場合は、好きなC++テクニックを使って動的な振る舞いを使ってOutOfMemoryHandlerに振る舞いを追加します。

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

関連する問題