02
07
g++で、コンストラクタが2種、デストラクタが3種生成される。
2011.02.07(21:57)
WindowsXP / Cygwin の環境で
bash-4.1$ g++ -v
gcc version 4.3.4 20090804 (release) 1 (GCC)
で以下のようなソースコード
main.cpp
Foo.h
Foo.cpp
をコンパイルするMakefile
を作ってビルドして
できた.oファイルをnmで調べてみると、
のように、コンストラクタが2種ずつ、デストラクタが3種類生成されます。
引数なしのコンストラクタは
00000060 T __ZN3FooC1Ev
00000088 T __ZN3FooC2Ev
intの引数ありのコンストラクタは
00000014 T __ZN3FooC1Ei
0000003a T __ZN3FooC2Ei
デストラクタは、
000000b0 T __ZN3FooD0Ev
000000e2 T __ZN3FooD1Ev
00000114 T __ZN3FooD2Ev
となります。
C++言語は、C言語と同等のコードサイズになる(ほんの少ししか違わない)と主張したい私にとって、コンストラクタやデストラクタが書いたコードの3倍とか2倍になることは当然許したくありません。
呼び出している側を見ると、
nm main.o
U __ZN3FooC1Ei
U __ZN3FooD1Ev
となっており、使っているのは、C1がついているコンストラクタと、D1がついているデストラクタだけです。
そもそも、どうしてコンストラクタが3種、デストラクタが2種できるのか知りたいです。さらに、
私の希望は、以下の(1)または(2)のどちらかができればいいのですが、どちらの方法もまだ見つかっていません。
(1) g++コンパイル時に使わないコードが生成されないようにする。
(2) .oファイル中でどこでも使われていないオブジェクトを削除する。
う~ん、困った。
逆アセンブルもしてみました。
同じコードを2回生成しているように見えます。
どうしてこんな無駄を生成するのでしょう?
bash-4.1$ g++ -v
gcc version 4.3.4 20090804 (release) 1 (GCC)
で以下のようなソースコード
main.cpp
#include "stdio.h" #include "Foo.h" int main(int argc,char** argv) { Foo f(10); Foo* foo = new Foo(1); foo->update(); delete foo; }
Foo.h
class Foo { private: int m_num; public: Foo(); Foo(int num); virtual ~Foo(); virtual void update(void); };
Foo.cpp
#include "stdio.h" #include "Foo.h" Foo::Foo() { printf("Foo::Foo()\n"); m_num = 0; } Foo::Foo(int num) { printf("Foo::Foo(int)\n"); m_num = num; } Foo::~Foo() { printf("Foo::~Foo()\n"); } void Foo::update(void) { printf("Foo::Update()\n"); }
をコンパイルするMakefile
# Makefile all: main.exe main.exe: main.o foo.o g++ -o main main.o foo.o main.o: main.cpp g++ -c main.cpp foo.o: foo.cpp g++ -c foo.cpp clean: rm -f main.o foo.o
を作ってビルドして
make clean make nm foo.o nm main.o
できた.oファイルをnmで調べてみると、
nm foo.o 00000000 T __ZN3Foo6updateEv 00000014 T __ZN3FooC1Ei 0000003a T __ZN3FooC2Ei 00000060 T __ZN3FooC1Ev 00000088 T __ZN3FooC2Ev 000000b0 T __ZN3FooD0Ev 000000e2 T __ZN3FooD1Ev 00000114 T __ZN3FooD2Ev 00000000 R __ZTI3Foo 00000000 R __ZTS3Foo 00000000 R __ZTV3Foo
のように、コンストラクタが2種ずつ、デストラクタが3種類生成されます。
引数なしのコンストラクタは
00000060 T __ZN3FooC1Ev
00000088 T __ZN3FooC2Ev
intの引数ありのコンストラクタは
00000014 T __ZN3FooC1Ei
0000003a T __ZN3FooC2Ei
デストラクタは、
000000b0 T __ZN3FooD0Ev
000000e2 T __ZN3FooD1Ev
00000114 T __ZN3FooD2Ev
となります。
C++言語は、C言語と同等のコードサイズになる(ほんの少ししか違わない)と主張したい私にとって、コンストラクタやデストラクタが書いたコードの3倍とか2倍になることは当然許したくありません。
呼び出している側を見ると、
nm main.o
U __ZN3FooC1Ei
U __ZN3FooD1Ev
となっており、使っているのは、C1がついているコンストラクタと、D1がついているデストラクタだけです。
そもそも、どうしてコンストラクタが3種、デストラクタが2種できるのか知りたいです。さらに、
私の希望は、以下の(1)または(2)のどちらかができればいいのですが、どちらの方法もまだ見つかっていません。
(1) g++コンパイル時に使わないコードが生成されないようにする。
(2) .oファイル中でどこでも使われていないオブジェクトを削除する。
う~ん、困った。
逆アセンブルもしてみました。
bash-4.1$ objdump -d Foo.o 00000060 <__ZN3FooC1Ev>: 60: 55 push %ebp 61: 89 e5 mov %esp,%ebp 63: 83 ec 08 sub $0x8,%esp 66: 8b 45 08 mov 0x8(%ebp),%eax 69: c7 00 08 00 00 00 movl $0x8,(%eax) 6f: c7 04 24 1c 00 00 00 movl $0x1c,(%esp) 76: e8 00 00 00 00 call 7b <__ZN3FooC1Ev+0x1b> 7b: 8b 45 08 mov 0x8(%ebp),%eax 7e: c7 40 04 00 00 00 00 movl $0x0,0x4(%eax) 85: c9 leave 86: c3 ret 87: 90 nop 00000088 <__ZN3FooC2Ev>: 88: 55 push %ebp 89: 89 e5 mov %esp,%ebp 8b: 83 ec 08 sub $0x8,%esp 8e: 8b 45 08 mov 0x8(%ebp),%eax 91: c7 00 08 00 00 00 movl $0x8,(%eax) 97: c7 04 24 1c 00 00 00 movl $0x1c,(%esp) 9e: e8 00 00 00 00 call a3 <__ZN3FooC2Ev+0x1b> a3: 8b 45 08 mov 0x8(%ebp),%eax a6: c7 40 04 00 00 00 00 movl $0x0,0x4(%eax) ad: c9 leave ae: c3 ret af: 90 nop
同じコードを2回生成しているように見えます。
どうしてこんな無駄を生成するのでしょう?