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
#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回生成しているように見えます。
どうしてこんな無駄を生成するのでしょう?

コメントの投稿

非公開コメント

プロフィール

島敏博

Shima Toshihiro 島敏博
信州アルプスハイランド在住。HaskellとElixirが好き。組み込みソフトウェアアーキテクト、C++プログラマ、山歩き、美術館巡り、和食食べ歩き、日本赤十字社救急法指導員、インデックス投資、クラシック音楽、SESSAME会員、状態マシン設計、モデル駆動開発、ソフトウェアプロダクトライン、Rubyist、実践ビジネス英語

■ ツイッター
http://twitter.com/saltheads
■ Facebook
http://www.facebook.com/saltheads
■ Qiita
http://qiita.com/saltheads

印刷する場合は、ブラウザの印刷メニューではなく、このページの上から3cmくらいの青いところにある、「印刷」を押してみてください。少しうまく印刷できます。まだ完全ではないのですが、これで勘弁してください。


カテゴリ
最新記事
月別アーカイブ
最新コメント
検索フォーム
リンク
sessame
RSSリンクの表示