今朝、同僚と静的変数の初期化順序について話し合いました。彼はNifty/Schwarzカウンターについて言及しましたが、私は(一種の)困惑しています。私はそれがどのように機能するかを理解していますが、これが技術的に言えば、標準に準拠しているかどうかはわかりません。
次の3つのファイルを想定します(最初の2つはMore C ++ Idiomsからコピーパスタされています)。
//Stream.hpp
class StreamInitializer;
class Stream {
friend class StreamInitializer;
public:
Stream () {
// Constructor must be called before use.
}
};
static class StreamInitializer {
public:
StreamInitializer ();
~StreamInitializer ();
} initializer; //Note object here in the header.
//Stream.cpp
static int nifty_counter = 0;
// The counter is initialized at load-time i.e.,
// before any of the static objects are initialized.
StreamInitializer::StreamInitializer ()
{
if (0 == nifty_counter++)
{
// Initialize Stream object's static members.
}
}
StreamInitializer::~StreamInitializer ()
{
if (0 == --nifty_counter)
{
// Clean-up.
}
}
// Program.cpp
#include "Stream.hpp" // initializer increments "nifty_counter" from 0 to 1.
// Rest of code...
int main ( int, char ** ) { ... }
...そしてここに問題があります!2つの静的変数があります。
Stream.cpp
;の"nifty_counter" と- の「初期化子」
Program.cpp
。
2つの変数はたまたま2つの異なるコンパイル単位にあるため、のコンストラクターが呼び出される前に0に初期化される(AFAIK)公式保証はありません。nifty_counter
initializer
私は2つの簡単な解決策を、これが「機能する」理由の2つと考えることができます。
- 最新のコンパイラは、2つの変数間の依存関係を解決し、実行可能ファイル内でコードを適切な順序で配置するのに十分なほど賢いです(ほとんどありません)。
nifty_counter
記事にあるように、実際には「ロード時」に初期化され、その値は実行可能ファイルの「データセグメント」にすでに配置されているため、常に「コードが実行される前」に初期化されます(可能性が高い)。
これらは両方とも、非公式でありながら可能な実装に依存しているように私には思えます。この標準は準拠していますか、それとも「機能する可能性が非常に高い」ので、心配する必要はありませんか?