正直日記



2008/01/27

_ 時を同じくして、新たな問題が
http://www.jitu.org/~tko/cgi-bin/bakagaiku.rb?bakaid=20080127

エラーメッセージは以下の通りなので、キャストすれば通るとして……

error: conditional expression between distinct pointer types `ChildA*' and `ChildB*' lacks a cast
ちょっとコードを変更してみる。
class Parent
{
  public: virtual ~Parent() { printf("~Parent\n"); };
};
class ChildA : public Parent
{
  public: virtual ~ChildA() { printf("~ChildA\n"); }; 
};
class ChildB : public Parent 
{
  public: virtual ~ChildB() { printf("~ChildB\n"); }; 
};

Parent*
doit(int n)
{
    return (n & 1) ? reinterpret_cast<Parent*> (new ChildA()) 
                   : reinterpret_cast<Parent*> (new ChildB());
}

int main()
{
    Parent* pa = doit( 0 );               // ChildBが返ると思うんだ
    ChildA* ca = reinterpret_cast<ChildA*>(pa);
    ChildB* cb = reinterpret_cast<ChildB*>(pa);
    printf("Parent pa:%p\n", pa);
    printf("ChildA ca:%p\n", ca);
    printf("ChildB cb:%p\n", cb);
    delete ca;

    pa = doit( 1 );                       // ChildAが返ると思うんだ
    ca = reinterpret_cast<ChildA*>(pa);
    cb = reinterpret_cast<ChildB*>(pa);
    printf("Parent pa:%p\n", pa);
    printf("ChildA ca:%p\n", ca);
    printf("ChildB cb:%p\n", cb);
    delete cb;

    return 0;
}
としたとき、結果が……
Parent pa:0x2000010
ChildA ca:0x2000010
ChildB cb:0x2000010
~ChildB
~Parent

Parent pa:0x2000010
ChildA ca:0x2000010
ChildB cb:0x2000010
~ChildA
~Parent
ふおおお、爆発する! C++ が爆発する! そんなの当たり前だろと言われそうだけどちょっと感動した! しかしこちらも、結局、中で何が起こって解決されてるのか分からない。 今度はポインタの指している値も一緒だし。 まぁ、いいか……。
_ ポインタの値が変わってどうなるのか想像つかない
http://alohakun.blog7.fc2.com/blog-entry-891.html
http://d.hatena.ne.jp/kmaebashi/20080121

おぉーなるほど。
とか言って、実はまだイマイチ分かってなかったり。

C から B にキャストした b を delete したときも、結局 ~C, ~B, ~A の順番で
デストラクタが呼ばれるなら、中身は一緒でいいんじゃないの?なぜポインタを
変える必要が?と思ってしまうのでした。

なんつーか、vtblがあるからってことは分かっても、そこから先で具体的に何を
してるのかってのが、いまいち想像できない。

想像できないなら答えを見ればいいじゃん、というわけで、メモリを覗くことで
表層から強引に理解してみようかと。理解出来たらいいなーくらいの気持ちで。

--

先に書いておくと、アサッテの方角へ向かって無駄な努力をした挙句に
結局なにも分からなかったので、というか何が分からないのかすら分から
ない状態になったので、理解済みの人は、 Ctrl-W をおして下さいね!

--

casttest.gbaを実行して、エミュレータのデバッグログから *a と *b を得る。
(VisualboyAdvance の Tools → Logging)

CTOR A
CTOR B
CTOR C
c:0x2000010
b:0x2000014
a:0x2000010
DTOR C
DTOR B
DTOR A

で、nm と map の出力を併せて読むと、ここらへんか。
08010a84 V _ZTV1A     0x10  vtable for A
08010a94 V _ZTV1B     0x10  vtable for B

とりあえず A の方を制覇していこう。 _ZTV1A こと vtable for A は……
08010a74 V _ZTI1A      0x8  typeinfo for A
0800f830 W _ZN1AD1Ev  0x18 A::~A()
0800f848 W _ZN1AD0Ev   0x24 A::~A()
もう A::~A() が登場しちゃったよ。早くね? でも無視して _ZTI1A こと typeinfo for A を見て行く。
なので……
08010b38 V _ZTVN10__cxxabiv117__class_type_infoE
                       0x2c vtable for __cxxabiv1::__class_type_info
08010a7c V _ZTS1A      0x4  typeinfo name for A
名前マングリング・ベイのアホー。 やたら長い名前の方は libstdc++.a(tinfo.o) から持ってきているのか。 無視して _ZTS1A を……っと、中身は 0x4131 と書いてあるだけだった。 やったー! A の終着点ですよ! でも、この数字が何を意味しているのかは想像できません!(当たり前だ) 巻き戻って vtable for B を追ってみる……
08010a68 V _ZTI1B      0x8  typeinfo for B
0800f86c W _ZN1BD1Ev   0x18 B::~B()
0800f884 W _ZN1BD0Ev   0x24 B::~B()
しかるのち
08010b38 V _ZTVN10__cxxabiv117__class_type_infoE
                       0x2c vtable for __cxxabiv1::__class_type_info
08010a70 V _ZTS1B      0x4  typeinfo name for B
_ZTS1B は…… 0x4231 ですね!やったー! ついでに _ZTS1C0x4331 でしたよ!やったったー!るんぱっぱー! あぁ……たぶん __cxxabiv1::__class_type_info で何かしら解決してるんだろ うけど……。ごめん。もう限界だ。さようなら。

> ダラダラ書いた後で思ったけど 別にメモリを直接覗かなくても、ポインタの中身を出力させて、あとは .elf を objdump で追えば良かったっぽい。  (2008/01/28 00:27:29)

最新
2010 | 01 04
2009 | 01 02 03 04 05 06 07 09 10 11 12
2008 | 01 02 03 04 05 06 07 08 09 10 11 12
2007 | 02 03 04 05 06 07 08 10 11 12
2006 | 01 02 03 04 05 06 07 08 09 10 11 12
2005 | 01 02 03 04 05 06 07 08 09 10 11 12