2012-02-11 38 views
2

巨大なコードベースにバグを修正している間に、参照の動的タイプが元のDerivedタイプからBaseタイプに変わったという奇妙な状況が観察されています。私はこの問題を説明するために、最小限のコードを提供しています:dynamic_cast <>のどのような状況や状況で失敗する可能性がありますか?

​​

funcptrは、関数ポインタ(void (*)(SomeClass&))です。 funcptrは非常に多くの機能を指すことができ、独自のコールフローを持っているため、デバッグは困難です。

関数ポインタの呼び出しの後で、派生型refDerivedからBaseに変わるのは非常に奇妙です。私の仕事を楽にするために、私はDerivedからBaseにオブジェクトのスライスを疑ったので、~Base()を純粋なvirtualとし、ソースコード全体を再コンパイルしました。コンパイラエラーはありませんでした。つまり、Baseのオブジェクトが宣言されていません。

refDerivedの動的タイプがBaseに変更され、dynamic_castが後で失敗する可能性がある理由は何ですか?

+2

typeid(ref)が呼び出しの後のベースである場合、その関数はオブジェクトを使いこなしています。あなたはオブジェクトにポインタを渡しているので、オブジェクト全体にランダムなものを書くのは非常に簡単です。 –

+0

@ LokiAstariは、このコードは数年間安定していますが、あなたが主に言ったのは私の主な容疑者です。 'pVoid'はそれを乱すかもしれないが、私はどのような状況でそれが起こっているのか見なければならない。その前に、参照のために動的型を静的型に変更する可能性のある些細なことがないかどうかを確認したいと思いました。 – iammilind

答えて

2

私は上記のコードは、実際にはコード例がコンパイルされていないためだとは思わない! dynamic_cast<Base*>(&ref)の結果であるBase*を暗黙的にDerived*に変換することはできません。

これは、typeid()の出力が実際に正しいと言われており、参照のタイプIDの変更可能な説明がいくつかあります。これらの全ては何らかの形でプログラム内のエラーを示している。

  1. 呼び出された関数はオブジェクトを破壊する。道徳的に同等のものをdynamics_cast<Base*>(obj.pVoid)->~Base()と呼んでいます。
  2. obj.pVoidが指すアドレスに、newの配置を使用して、つまりnew(obj.pVoid) Base()のような新しいオブジェクトが作成されます。
  3. 何かがメモリを上書きしているため、参照先の場所にBaseオブジェクトが残っています。
  4. 私はケースである第2の場合に賭けることになる、...おそらく個人

複数の理由があり、すなわち、オブジェクトが位置に構成されています。明らかに、呼び出される関数を見ることなく、伝えることは不可能です。

+0

これはタイプミスで、私は 'dynamic_cast (&ref)'に編集しました。理由(2)は、私がすでに言及した理由のために不可能かもしれません。私は 'Base ::〜Base()'を純粋な 'virtual'とし、コードを再コンパイルしましたが、コンパイルエラーはありませんでした。つまり、 'Base'クラスのオブジェクト作成はありません。 – iammilind

2

dynamic_cast(ポインタまで)は、変換があいまいである場合は0を返すことができます。説明する:

class O {…}; 
class A : public virtual O {…}; 
class B : public A {…}; 
class C : public A {…}; 
class D : public B, public C {…}; 


void f(O& p) { 
    A* const a(dynamic_cast<A*>(&p)); 
} 

void g() { 
    D d; 
    f(d); 
} 
+0

この場合、多重継承はありません。また、たとえそれがあったとしても、私の場合は影響を与えません。関数呼び出しの前には、 'Base&ref'の動的型が' Derived'でした。だからそれはそのまま残っていたはずです。 – iammilind

+0

@ iammilind ok。それが他人を助ける場合に備えて私はそれを残すでしょう。考えてみましょう:パラメータの仮想の1つ(またはそれ以上)への呼び出しを追加し、実際に何が実行されて型を決定するのかを調べることができます(またはおそらくメモリを掘り起こすでしょうか?)。あなたが持っているプログラムによっては、手がかりになるかもしれません。可視性を低下させる(またはメソッドを削除する)ことは、時には助けになります。 – justin

0

具体的にはdynamic_cast<>が失敗したのは、deleteが早すぎるためです。

ポインタまたは参照がdelete +破壊されたら、次に、元の型にそれをダウンキャストしようとすると、「未定義の動作」領域に入ることになります。私の場合、dynamic_cast<>は失敗しています。

+0

これはちょうどUB – paulm

+1

@paulmです。はい、この回答ではすでに太字で記載されています。 – iammilind

関連する問題