仮想関数テーブルが 0 を指しているオブジェクトで仮想関数を呼び出そうとするために発生する、アプリケーションでのアクセス違反を分析しています。そのため、オブジェクトの有効期間のどの時点で仮想関数テーブルが存在するかを知りたいです。ポインタが設定されていないか、明示的にゼロに設定されていますか?
(コンパイラはVisual C++ 10を使用しています。)
仮想関数テーブルが 0 を指しているオブジェクトで仮想関数を呼び出そうとするために発生する、アプリケーションでのアクセス違反を分析しています。そのため、オブジェクトの有効期間のどの時点で仮想関数テーブルが存在するかを知りたいです。ポインタが設定されていないか、明示的にゼロに設定されていますか?
(コンパイラはVisual C++ 10を使用しています。)
オブジェクトが有効な状態にある間、vtable ポインターが 0 になることはありません。構築と破棄の間、オブジェクトは抽象基本クラスの動的型を持ちますが、vtable は純粋仮想関数を含む抽象基本クラス vtable を指しますが、vtable ポインター自体はゼロ以外のままです。
vtable ポインターがゼロになるのは、構築前または破棄後のみです。
vtable ポインターが本当にゼロの場合は、次のような VC++ 拡張機能を使用した可能性があります。
class __declspec(novtable) Base {
public:
Base();
virtual void proc();
};
ここで__declspec(novtable)
は、派生クラスが独自の vtable をインストールするまで仮想関数が呼び出されないため、クラスが vtable を必要としないことをコンパイラに伝えます。その前に Base::proc() を呼び出すと、エラーが発生する可能性があります。
おそらく、vtable 自体はゼロではありませんが、関数が純粋な仮想であるため、その中の関数のスロットはゼロです。
class Base {
public:
virtual void proc() = 0;
};
とにかく誰かが次のようなコードでそれを呼び出しました:
void Derived::proc() {
Base::proc();
// Derived-specific stuff here.
};
これは、Derived の作成者が、Base バージョンが存在しないにもかかわらず、Base バージョンを呼び出すためにオーバーライドが必要であると想定したために発生する可能性があります。
いずれにせよ、これを見つけるための 1 つのアプローチは、すべての基本クラスの悪ふざけを止め、関数を通常どおりに定義し、それを呼び出すものを確認することです。例えば:
class Base {
public:
virtual void proc() {
assert( typeof(*this) != typeof(Base) ); // Break-point here.
}
};