その2の続き。今度は条件付き。

最初に初期化したい変数(のコンストラクタ)からアプリケーションの他の部分を呼ばないのであれば、変数をライブラリに追い出すことで先に初期化させることができます。これは言語仕様ではなくリンカの挙動に依存する動作ですが、実際問題としてライブラリ部分が先に初期化されてもらわないとかなり困るので、ここは依存してもいいのではないかと思います。

/* a.h */
#include <iostream>

class A
{
	const char *s;
public:
	A(const char *ss) : s(ss) { std::cout << s << ".A()\n"; }
	~A() { std::cout << s << ".~A()\n"; }
	void p() { std::cout << s << ".p()\n"; }
};
/* a.cc */
#include "a.h"

A a("a");

extern A b;

int main(void)
{
	a.p();
	b.p();
}
/* b.cc */
#include "a.h"

A b("b");
[umezawa@nyx:pts/1 initorder]$ g++ -c b.cc
[umezawa@nyx:pts/1 initorder]$ ar rcs libb.a b.o
[umezawa@nyx:pts/1 initorder]$ g++ -o a -L. a.cc -lb
[umezawa@nyx:pts/1 initorder]$ ./a
b.A()
a.A()
a.p()
b.p()
a.~A()
b.~A()

が、同じことを OSX で実行するとこんなことになります。

[umezawa@metis:ttys000 initorder]$ ./a
a.A()
b.A()
a.p()
b.p()
b.~A()
a.~A()

ええっ

うろたえつつ Visual C++ + Windows でやってみるとこうなります。

N:\initorder>cl /c /EHsc b.cc
N:\initorder>lib /OUT:libb.lib b.obj
N:\initorder>cl /EHsc a.cc libb.lib /link /LIBPATH:.
N:\initorder>a.exe
a.A()
b.A()
a.p()
b.p()
b.~A()
a.~A()

なんてこったい。依存しちゃいけないのか。

もっとも、さすがにシェアードライブラリ(Windows では DLL、OSX では dylib)なら大丈夫なようです。

[umezawa@metis:ttys000 initorder]$ g++ -shared -o libb.dylib b.cc
[umezawa@metis:ttys000 initorder]$ g++ -o a -L. a.cc -lb
[umezawa@metis:ttys000 initorder]$ ./a
b.A()
a.A()
a.p()
b.p()
a.~A()
b.~A()
(あらかじめ __declspec(dllexport/dllimport) を適切に付けておく)
N:\initorder>cl /LD /EHsc b.cc
N:\initorder>cl /EHsc a.cc b.lib /link /LIBPATH:.
N:\initorder>a.exe
b.A()
a.A()
a.p()
b.p()
a.~A()
b.~A()

狼狽が隠しきれません。

Trackback

no comment untill now

Add your comment now