3

A colleague of mine had a problem with some C++ code today. He was debugging the weird behaviour of an object's virtual method. Whenever the method executed ( under debug, Visual Studio 2005 ), everything went wrong, and the debugger wouldn't step in that method, but in the object's destructor! Also, the virtual table of the object, only listed it's destructor, no other methods.

I haven't seen this behaviour before, and a runtime error was printed, saying something about the ESP register. I wish I could give you the right error message, but I don't remember it correctly now.

Anyway, have any of you guys ever encountered that? What could cause such behaviour? How would that be fixed? We tried to rebuild the project many times, restarted the IDE, nothing helped. We also used the _CrtCheckMemory function before that method call to make sure the memory was in a good state, and it returned true ( which means ok ) . I have no more ideas. Do you?

4

5 に答える 5

2

私は前にそれを見たことがあります。通常、これは、デバッグモードでリリースビルドの.LIBファイルのクラスを使用しているために発生します。他の誰かがおそらくより良い例を見たので、私は彼らの答えに私の答えを与えるでしょう。

于 2010-01-07T21:33:32.550 に答える
1

間違った数のパラメーターを使用して関数を呼び出すと、スタックが破壊され、未定義の動作が発生する可能性があります。MFCを使用する際の特定のエラーは、これを簡単に引き起こす可能性があることを思い出しているようです。たとえば、ディスパッチマクロを使用して、適切な数またはタイプのパラメーターを持たないメソッドにメッセージをポイントする場合(これらの関数を思い出しているようです)ポインタのタイプは厳密にはチェックされません)。私が最後にその特定の問題に遭遇してからおそらく10年が経ちました、それで私の記憶はぼんやりしています。

于 2010-01-07T22:09:13.230 に答える
1

a が必要な場所で C スタイルのキャストを使用している可能性static_cast<>がありますか? これにより、複数の継承が関係する場合は常に、報告したようなエラーが発生する可能性があります。たとえば、次のようになります。

class Base1 {};
class Base2 {};
class Derived : public Base1, public Base2 {};

Derived *d = new Derived;
Base2* b2_1 = (Base2*)d; // wrong!
Base2* b2_2 = static_cast<Base2*>(d); // correct
assert( b2_1 == b2_2 ); // assertion may fail, because b2_1 != b2_2

これは常に当てはまるとは限らないことに注意してください。これは、コンパイラーおよび関連するすべてのクラスの宣言に依存します (すべてのクラスに仮想メソッドがある場合に発生する可能性がありますが、正確なルールは手元にありません)。

または: コードのまったく別の部分が暴走し、メモリを上書きしています。エラーを分離して、それでも発生するかどうかを確認してください。CrtCheckMemoryメモリを上書きするいくつかのケース (たとえば、特別にマークされたヒープ管理場所に書き込む場合) のみが見つかります。

于 2010-01-07T22:02:14.693 に答える
1

関数呼び出しで ESP の値が適切に保存されませんでした。

この種の動作は通常、問題の特定のクラスを作成したコードとは異なるクラスまたは関数の定義でコンパイルされた呼び出し元のコードを示しています。

新しくビルドされたものではなく、別のバージョンのコンポーネント dll がロードされている可能性はありますか? LoadLibraryこれは、ビルド後の手順の一部としてコピーした場合、またはプロセスが別のディレクトリから実行された場合、または同等の処理を実行する前に dll 検索パスを変更した場合に発生する可能性があります。

クラス定義が変更されて仮想関数の署名が追加、削除、または変更された後、インクリメンタル ビルドが行われ、再コンパイルが必要なすべてのコードが実際に再コンパイルされるわけではない、複雑なプロジェクトで最も頻繁に遭遇しました。理論的には、プログラムの一部がいくつかのポリモーピック オブジェクトの vptr または vtables を上書きしている場合に発生する可能性がありますが、部分的なビルドが悪いことが原因である可能性がはるかに高いことが常にわかっています。

これは「ユーザー エラー」である可能性があります。開発者は、他のプロジェクトを再ビルドする必要がある場合に 1 つのプロジェクトのみをビルドするように意図的にコンパイラに指示するか、依存関係が正しく設定されていないソリューションに複数のソリューションまたは複数のプロジェクトが含まれている可能性があります。

ごくまれに、ソリューション内のプロジェクトが正しくリンクされている場合でも、Visual Studio が誤って生成された依存関係を正しく取得できないことがあります。これは、Visual Studio が原因であると非難されるほど頻繁には発生しません。

すべての中間ビルド ファイルを消去し、ソースからすべてを再構築すると、通常は問題が解決します。明らかに、非常に大規模なプロジェクトでは、これは深刻なペナルティになる可能性があります。

于 2010-01-07T23:04:01.527 に答える
1

とにかく推測なので、ここに私からの1つがあります:

スタックがめちゃくちゃになって_CrtCheckMemoryいて、それをチェックしていません。スタックが破損している理由について:

  • 古き良きスタックオーバーフロー
  • 既に述べた呼び出し規約の不一致 (私にはわかりません。たとえば、間違った呼び出し規約でコールバックを WinAPI 関数に渡すなどです。どの静的ライブラリまたは動的ライブラリとリンクしていますか?)
  • のような行printf("%d");
于 2010-01-08T00:59:07.210 に答える