基本クラスのデストラクタの this-pointer に奇妙な問題があります。
問題の説明:
私は3つのクラスを持っています: A1、A2、A3
A2はA1からパブリックに継承し、 A3からプライベートに継承します
class A2:private A3, public A1 {...}
A3には関数getPrimaryInstance()があります ... A2インスタンスへのA1タイプの参照を返します。
A1& A3::getPrimaryInstance()const{
static A2 primary;
return primary;
}
A3コンストラクターは次のようになります。
A3(){
getPrimaryInstance().regInst(this);
}
( regInst(...)は、すべてのA3インスタンスへのポインターを格納するA1で定義された関数です)
同様にA3デストラクタ:
~A3(){
getPrimaryInstance().unregInst(this);
}
↑ここで問題発生!
primaryという名前の静的なA2インスタンスがプログラムの終了時に破棄されると、 A3デストラクタが呼び出されますが、~A3内では、破棄するのと同じインスタンスの関数にアクセスしようとします。 =>実行時のアクセス違反!
したがって、次のような単純なifステートメントで修正できると思いました。
~A3(){
if(this != (A3*)(A2*)&getPrimaryInstance()) //Original verison
//if (this != dynamic_cast<A3*>(static_cast<A2*>(&getPrimaryInstance())))
//Not working. Problem with seeing definitions, see comments below this post
getPrimaryInstance().unregInst(this);
}
(二重キャストの理由は継承です:)
A1 A3
. \ /
. A2
(しかし、それは重要ではありません。単に(int)キャストなどを使用できます)
キッカーは、それがまだクラッシュすることです。デバッガーでコードをステップ実行すると、A2 プライマリインスタンスが破棄されたときに、デストラクタのthisポインターとgetPrimaryInstance()を呼び出して取得したアドレスが何らかの理由でまったく一致しないことがわかります。this -pointer が指すアドレスが、(私の限られた知識では) あるべきアドレスと常に異なる理由を理解できません。:(
デストラクタでこれを行う:
int test = (int)this - (int)&getPrimaryInstance();
また、違いが一定ではないことも示しました(一定のオフセットがあるという理論が簡単にありました)ので、同じものであるはずの2つの完全に異なるオブジェクトのようです。:(
私は VC++ Express (2008) でコーディングしています。少しグーグルで調べた後、次の MS 記事を見つけました:
FIX: The "this" Pointer Is Incorrect in Destructor of Base Class
これは私が抱えている問題とは異なります (また、C++.Net 2003 で修正されたと思われます)。しかし、症状は非常に似ているように見え、簡単な回避
策が提示されたので、
試してみることにしました.
class A2:private A3, public A1 {...} // <-- old version
class A2:private A3, virtual public A1 {...} //new, with virtual!
そしてそれはうまくいきました!this -pointerはまだ間違っているように見えますが、アクセス違反は発生しなくなりました。
だから私の大きな質問はなぜですか?this
-pointer が本来あるべき場所を指していない
のはなぜですか? 上記のように継承にvirtualを
追加すると解決するのはなぜですか(これはまだ&getPrimaryInstance()以外の場所を指しているにもかかわらず)?
これはバグですか?MS 以外の環境で試すことはできますか?
そして最も重要なこと:これは安全ですか?? 確かにもう文句は言いませんが、私はまだそれがすべきことをしていないのではないかと心配しています. :S
誰かがこれについての知識や経験を持っていて、それを理解するのを手伝ってくれるなら、私はとても感謝しています.