More C++ Idioms/小粋なカウンタ(Nifty Counter)
小粋なカウンタ(Nifty Counter)
編集
意図
編集非ローカル静的オブジェクトがその最初の使用時より前に初期化され、また最後の使用の後にのみ破壊されることを保証する。
別名
編集動機
編集静的オブジェクトが別の静的オブジェクトを使用する場合、初期化の問題はより複雑になる。静的オブジェクトが自明でない(non-trivial)初期化処理を持つ場合、使用前に初期化されなければならない。翻訳単位間での静的オブジェクトの初期化順序は厳密には定義されていない。複数の翻訳単位にまたがる複数の静的オブジェクトが単一の静的オブジェクトを使用するかもしれない。例えば、std::cout が考えられる。std::cout は他のいかなる数の静的オブジェクトにも使用されうる。そのため使用前に初期化されなければならない。
解法とサンプルコード
編集小粋なカウンタ(Nifty counter)イディオムは、静的順序の初期化に参照カウントイディオムを適用した例である。
//Stream.hpp
class StreamInitializer;
class Stream {
friend class StreamInitializer;
public:
Stream () {
// コンストラクタは使用前に呼び出されなければならない。
}
};
static class StreamInitializer {
public:
StreamInitializer ();
~StreamInitializer ();
} initializer; // このオブジェクトはヘッダにあることに注意せよ。
//Stream.cpp
static int nifty_counter = 0;
// ロード時、すなわちどの静的オブジェクトの初期化よりも前に、カウンタは初期化される。
StreamInitializer::StreamInitializer ()
{
if (0 == nifty_counter++)
{
// Stream オブジェクトの静的メンバを初期化する。
}
}
StreamInitializer::~StreamInitializer ()
{
if (0 == --nifty_counter)
{
// 後始末。
}
}
Stream クラスのヘッダファイルは、Stream オブジェクトのメンバ関数呼び出しが発生しうるよりも前に include されなければならない。StreamInitializer クラスのインスタンス(イニシャライザ)は各翻訳単位に含まれる。Stream オブジェクトの使用はヘッダの include の後に発生する。これにより、イニシャライザオブジェクトのコンストラクタが Stream オブジェクトが使用される前に呼び出されることが保証される。
既知の利用
編集C++ 標準の iostream ライブラリ std::cout, std::cin, std::cerr, std::clog