2012-01-18 20 views
0

私はちょうどthis questionに尋ねました。要するに、win32タイマーのコールバックからスローすると、その例外はどこにも出てこないように見えます。それはWindowsのどこかで秘密裏に扱われているようだ。win32タイマーコールバックを投げたときにデストラクタが呼び出されないのはなぜですか?

OKよく問題です。問題のもう一つの側面は、この例外がスローされたときにデストラクタが呼び出されていないように見えるということです。次のコードでは、CFooのの場合、GetFooVectの一時変数が破棄され、rValueがfooVectにコピーされたときに、 "〜CFoo"という唯一の時間が出力されます。 fooVectの内容は破壊されません。

これは私の最悪の悪夢です。私はかなりRAIIを使用します。私はデストラクタにかなり頼りにして、適切にクリーンアップします。

class CFoo 
{ 
public: 
    ~CFoo() {printf(__FUNCTION__ "\n");} 
}; 

std::vector<CFoo> GetFooVect() 
{ 
    std::vector<CFoo> rValue; 
    rValue.push_back(CFoo()); 
    rValue.push_back(CFoo()); 
    rValue.push_back(CFoo()); 
    return rValue; 
} 

VOID CALLBACK Timer(HWND hwnd, 
    UINT uMsg, 
    UINT_PTR idEvent, 
    DWORD dwTime) 
{ 
    // My destructors aren't called? 
    std::vector< CFoo> fooVect = GetFooVect(); 

    // I'm destroyed 
    CFoo aFoo; 

    throw FooExcept(); 
    printf("Also Here\n"); 
} 

私は単純にC++の例外(つまり、Win32のタイマーコールバック変数を削除)し、CFooの破棄のベクトルだけで罰金をキャッチ/スローすることによって、これを再作成しようとしました。なんらかの理由で、デストラクタはベクトルのもののためにここで呼び出されていません。何がありますか?これについて論理的な説明がありますか、それともちょっと変わったのでしょうか、あるいはその両方ですか?

答えて

6

SetTimerコールバックのように、C API境界を越えて例外が伝播することは絶対に許されるべきではありません。 Cコード(およびWindows API関数)はC++言語の例外について何も知らない。そのようなコードを使用して例外を伝播することはできません。

あなたのコールバックは、すべてのC++言語の例外をキャッチして戻って例外を適切に処理する必要があります。アプリケーションの残りの部分に何とか例外を通知する必要がある場合は、自分で行う必要があります。

(ここでは他の人がこの場合何が起こっているのかを詳しく説明することができますが、C++言語例外の存在下でCコードを使って正しいことをすることはできないという短い答えですが、これはC++言語の例外が何であるか分かりません)。

+0

+1:決してWin32コールバックまたはCOMインターフェイスメソッドから例外をスローしません。そうすることは本質的に未定義の動作です。これらのいずれかで例外を使用している場合は、戻る前に* everything *をキャッチしてから、通常の戻りコードを返します。例外を上位に伝播させたい場合は、他の場所に状態を保存し、APIを使用して正常に戻り、エラーをチェックして、コントロールが自分のコードに戻ったときに再びスローします。 – BrendanMcK

+0

ここで起こっている可能性がありますC++ランタイムは、例外の実装において低レベルの構造化例外処理(SEH)機能を使用しており、Win32のコードもSEHを使用していますが、独自の目的でC++ランタイムを妨害します。これは、C++の実行時に例外を実装するC++ランタイムがコンパイルするコードまたはコンパイラに同梱されているライブラリに対して「管轄」しか持たないためです。 Win32コードモジュールとDLLは独自の宇宙です。同様に、Win32やCOMから返される任意のオブジェクトではなく、独自のコードのオブジェクトに対してのみC++ RTTIを使用できます。 – BrendanMcK

+0

デストラクタは、ランタイムがC++ catchブロックを見つけるまで実行されません。もちろん、Timerコールバックの上にあるコールスタックではそれほど高くありません。 –

関連する問題