10

彼の「ThinkinginC++」(第10章)で、Eckelは、大失敗を解決するためにJerrySchwarzによって開拓された手法について説明しています。xを100に、yを200に初期化し、それらをすべての変換ユニット間で共有する場合は、次のようなInitializer.hを作成すると彼は言います。

extern int x;
extern int y;
class Initializer {
   static int initCount;
   // if (initCount++ == 0) x = 100 & y = 200
   /* ... */
};
static Initializer init;

そして、実装ファイルには

#include "Initializer.h"
int x;
int y;
int Initializer::initCount;

そしてEckelは、「(実装ファイル内の)静的初期化はこれらすべての値を強制的にゼロにする」と述べています。

次の場合を考えてみましょう。コンパイラは、そのヘッダーが含まれている他のファイルのに実装ファイルを処理します(つまり、他のファイルでxとyがすでに100と200に設定されていることを意味します)。コンパイラはを認識int xしますが、それは何をしますか?xとyをゼロに設定して、初期化と以前のファイルで発生する可能性のあるすべての変更を排除しますか?しかし、そうであれば、それinitCountもゼロに設定され、テクニック全体が分解されます。

4

5 に答える 5

4

しかし、それが真であり、コンパイラが別のファイルの後に実装ファイルを処理する場合、xとyをゼロに設定して、初期化と以前のファイルで発生する可能性のあるすべての変更を排除しますか?

これが何を意味するのかわかりません。xおよびが他のファイルで定義されている場合y、リンカーの衝突が発生し、プログラムは単にコンパイルされません。

xyそして最も重要なことに、このように実装されている場合Initializer::initCount、プログラム内にそれらの一意のインスタンスが存在します。それらは事実上グローバルであり0、プログラムの開始時に、構築されるに初期化されます(そのクラスInitializerのインスタンスを宣言するヘッダーが含まれているため)。staticの各構築は、最初に他の何かがなどのために構築されたstatic Initializerかどうかをチェックします。Initializerif (initCount++ == 0)

したがって、最初Initializerに実行するctor(まだ入力する前main)は、3つの値すべてを設定します。

于 2011-03-14T13:28:08.640 に答える
3

「Initializer」で行われるのは、初期化ではなく割り当てです(有効な構文を前提としています)。

そのため、そもそも大失敗がないため、特殊なケースの静的初期化順序の大失敗を「解決」します。xとyは整数であり、予測できないときに互いに呼び出さず、さらに同じ変換単位に存在します。コンパイラはそれらを適切に初期化します。後で定義された順序で値を割り当てることは問題ありませんが、それはより複雑であり、それ以上ではありません。

静的初期化順序の大失敗が表示されるには、次のような状況が必要になります。xのコンストラクターはyの値(またはその逆)を必要とし、それらは異なる変換単位にあります。したがって、これが機能するかどうかは50:50の確率です。

これで、「Initializer」構造体は定義された順序で値を正しく割り当てますが、その時点では、構築されていないものに割り当てることができないため、xとyのコンストラクターはすでに実行されています...したがって、問題が存在する場合は、問題を完全に回避してください。

この問題に対処する一般的な方法は、最初の使用時に構築することです。この手法には、次のようなさまざまなフレーバー(それぞれに長所と短所があります)があります。

x& get_x() { static x *xxx = new x(); return *xxx; }
于 2011-03-14T13:48:23.340 に答える
2

他のソースファイルのstatic-initスコープでの使用と初期化の可能性を意味すると仮定すると、絶対に正しいです。コンパイラがこのファイルの静的初期化を他のファイルで実行することを決定した場合は、他の作業を元に戻します。

多くの場合、グローバル/スタティックをまったく使用しないことで、非常に多くの頭痛の種を減らすことができます。

于 2011-03-14T13:44:15.767 に答える
1

プログラムがロードされると、コードが実行される前に、グローバルxとyがゼロに初期化されます。イニシャライザーが作成されると、xとyはすでにゼロに初期化されています。物事はこの順序で起こります:

  1. プログラムがロードされます
  2. グローバル変数と静的変数はゼロで初期化されます(xとyは0の値を取得します)
  3. グローバルオブジェクトが構築されます(Initializerはxとyを100と200に設定します)
于 2011-03-14T13:29:23.713 に答える
0

宣言しないのはなぜですか(ファイルスコープで、単一の翻訳単位で):

int x = 100;
int y = 200;

xとyはイメージの読み取り/書き込みセクションに格納されるため、プロセス内のコードが実行される前に初期化されます。プレーンオールドデータの初期化順序について心配する必要はありません。

于 2012-09-20T18:08:30.097 に答える