2010/08/03
ヘッダにstatic member
C++の class template を使えば static メンバの実体がヘッダファイルに書けるカラクリ - ひげぽん OSとか作っちゃうかMona
C++の class template を使えば static メンバの実体がヘッダファイルに書けるというテクニックがある。考えてみると不思議な動作に思える。だって分割コンパイルしたら実体が複数個出来そうじゃない?。この裏側で起こっている事を実験前に予想して試したところ、予想通りだったのでうれしかったのでメモを残す。
リンカがよしなに計らってくれるのか、なるほど。と思ったけど じゃあリンカの預かり知らぬところで共有されたらやばそうだよなあ。 例えばdlopenされるやつとか。
環境はgcc-4.4.3 on Ubuntu 10.04。
Hoge.h と a.cpp はひげぽんさんのと同じ。 b.cppはdlsym経由で 呼びやすいようにC linkageにしておく。
b.cpp:
#include "Hoge.h" extern "C" void funcB() { Hoge<bool> hoge; hoge.incrementAndShow(); }
mainはこんなかんじ。
main.cpp
#include <dlfcn.h> #include <stdio.h> #include <errno.h> extern void funcA(); void (*pfuncB)(); int main(int argc, char *argv[]) { funcA(); void *h = dlopen("./b.so", RTLD_NOW); if (!h) { perror("dlopen"); return 1; } pfuncB = (void (*)())dlsym(h, "funcB"); if (!pfuncB) { perror("dlsym"); return 1; } pfuncB(); dlclose(h); return 0; }
ビルドはこんなかんじ。
Makefile:
all : main b.so main : a.o g++ -o main main.cpp a.o -ldl b.so : b.o g++ -shared -o b.so b.o b.o : b.cpp g++ -fPIC -c b.cpp clean : rm -f main *.so *.o *~
実行結果。別々のHoge::counterの実体を見てる。
$ ./main counter = 1 counter = 1
まあ仕方ないっちゃ仕方ない話だけど。 外部APIとして見せるクラスでこのテクニックを使う場合は落とし穴になるかも。
(なお、b.cppを共有ライブラリlibb.soにしてmainリンク時に -lbでリンクした場合は、ちゃんとHoge::counterは共有される。)
理想的には、ランタイムがもっと賢くなって、 実行前の静的なリンク実行時の動的なリンクも同じように扱って くれればいいのかなあ。
Tags: Programming, C++
ひげぽん (2010/08/05 06:33:50):
shiro (2010/08/05 07:27:54):