8

組み込みOSの例外処理を実装しようとしていますが、スローされた「例外」のタイプを検出する方法(適切なハンドラーを選択するため)に固執しています。

例外処理のコンテキスト部分の保存と復元はすでに完了していますが、スローされた「例外」のタイプを検出できないため、特定のハンドルを持つことはできません。c ++の標準RTTI実装は他のライブラリに依存しすぎているため、現在は利用できないと考えています。

私のターゲットが組み込みシステムであり、そのため多くのコードを作成できないことを考えると、取得(または作成)できる「実行時型情報」の最小の実装は何ですか?

- 編集 -

私はコンパイラに取り組んでいません、それはia32-g++です。

4

2 に答える 2

11

組み込み環境で作業している場合、おそらく非常に最小限のソリューションを好み、コンパイラーに関する非標準または非移植性の事実を利用できます。

クラスがC++でポリモーフィック(独自の仮想関数を少なくとも1つ持つ)である場合、そのクラスのどこかにvtableへのポインターが埋め込まれている可能性があります。vtableポインタがメモリ内のオブジェクトのレイアウトの先頭に表示されている可能性があります。

これは多くのコンパイラに当てはまります。C++ABIを使用するコンパイラです。ここで関連するSOの質問です

その場合、次のようにvtableにアクセスできる可能性があります。

void *get_vtable(void *obj)
{
    return *(reinterpret_cast<void **>(obj));
}

次に、オブジェクトへの2つのポインターのvtableを比較して、それらが同じタイプのオブジェクトを指しているかどうかを確認できます。

したがって、「タイプスイッチ」(基本的にキャッチとは)は次のようになります。

P p;
Q q;
if (get_vtable(caught) == get_vtable(&p))
{
    // it's a P...
}
else if (get_vtable(caught) == get_vtable(&q))
{
    // it's a Q...
}

そのパターンをCATCHマクロで非表示にすることができます。

重要なポイント-ベースからクラスを派生させたが、派生クラスが仮想関数をオーバーライドしたり、新しい仮想関数を追加したりしない場合、コンパイラーは、派生クラスに対してベースクラスのvtableを再利用できると考えられます。つまり、2つの例外タイプを区別するには、それぞれが仮想関数をオーバーライドして、独自のvtableを確実に持つ必要があります。

これは、例外処理に含まれるもののほんの一部にすぎないことに注意してください。スタックをほどくという小さな問題もあります!ハンドラーにジャンプするときは、スタック上のすべてのオブジェクトのデストラクタを呼び出す必要があります。setjmp/longjmpを実行するだけの問題ではありません。

于 2009-07-03T22:06:56.587 に答える
2

私が考えることができる最も単純なRTTIは、純粋な仮想「GetType()」関数を持つ共通ベースからすべてのクラスを派生させることです。文字列を返すように取得するか、すべての型を含む巨大な列挙型を作成します。非常にシンプルで、高速で、メモリのオーバーヘッドが低くなっています。ただし、特に柔軟性はありません。

于 2009-07-03T21:54:57.110 に答える