シングルトンオブジェクトを表現しようとして以下のようなコードを書いたところ、

MenuCommandBuilder &
MenuCommandBuilder::instance()
{
    static MenuCommandBuilder instance_;
   
    return instance_;
}

以下のようにコンパイラに怒られました。

$ make
/usr/local/crossgcc/h8300-hms/bin/h8300-hms-ld main.o Calibrator.o Console.o Men
u.o Rcx.o Utility.o -T ../brickos/boot/brickOS.lds -relax -L../brickos/lib -lc -
lmint -lfloat -lc++ --oformat coff-h8300 -Ttext 0xb000 -o lego.dc1
Menu.o(.text+0x406):Menu.cpp: undefined reference to `atexit'
Menu.o(.text+0x406):Menu.cpp: undefined reference to `atexit'
Menu.o(.text+0x406):Menu.cpp: undefined reference to `atexit'
make: *** [lego.lx] Error 1

atexit がリンクできないことが原因。brickOS 側のソースを検索しても確かに実装されていない。試しに以下のコードをコンパイル・リンクすると通ります。

extern "C"
void atexit()
{
}

今 RCX が手元になくて動作を確認できてないので動くかどうかはわかりません。

ちなみにメンバ関数内 static 変数はダメだけど、内部リンケージにすると大丈夫という。

static MenuCommandBuilder *instance_ = 0;

MenuCommandBuilder &
MenuCommandBuilder::instance()
{
    if (!instance_)
        instance_ = new MenuCommandBuilder;
    return *instance_;
}

さらに、static メンバ変数にしても大丈夫。

MenuCommandBuilder *MenuCommandBuilder::instance_ = 0;

MenuCommandBuilder &
MenuCommandBuilder::instance()
{
    if (!instance_)
        instance_ = new MenuCommandBuilder;
    return *instance_;
}

というわけで、シングルトンを実現するには

  • 内部リンケージ変数をつかう
  • static メンバ変数をつかう

あたりで実装するよ、という話。