2

C++ では、静的変数を定数値ではなく変数値で初期化する合理的なコンパイラで予想されるランタイム コストはどれくらいですか?

たとえば、次のコードを検討してください。

bool foo();
bool baz1() {
  const bool value = foo();
  static bool alternate1 = value;
  static bool alternate2 = false;

  // Do something.
  return alternate1;
}

alternate1と の間で予想されるランタイム コストの差はalternate2いくらですか?

4

4 に答える 4

5

コンパイル時の定数 (代替 2) からの初期化は、ほとんどの場合、プログラムの起動時に行われ、関数が呼び出されるたびにコストはかかりません。

ローカル静的変数のスレッドセーフな初期化により、コンパイラは次の擬似コードのようなものを生成します。

static bool alternate1;

static bool __initialised = false;
static __lock_type __lock;
if (!__initialised) {
    acquire(__lock);
    if (!__initialised) {
        alternate1 = value;
        __initialised = true;
    }
    release(__lock);
}

そのため、関数が呼び出されるたびにフラグのテストが行​​われる可能性が高く (メモリ バリアやその他の同期プリミティブが関与している可能性があります)、最初にロックを取得して解放するためのコストがさらにかかります。

foo()コードでは、変数がまだ初期化されているかどうかに関係なく、毎回呼び出されることに注意してください。初期化を次のように変更した場合、最初にのみ呼び出されます

static bool alternate1 = foo();

もちろん、詳細は実装に依存します。これは、GCC によって生成されたコードの観察に基づいています。

于 2012-07-10T13:56:34.097 に答える
1

あなたの質問は一般的に静的変数に関するものではなく、関数内で宣言された静的変数に関するものであるようです。

ランタイム値からそのような変数を初期化するための追加のランタイム コストは、いくつかの原因に起因します。

  1. このような変数は、コントロールがその宣言を最初に渡すときに (もしあれば) 1 回だけ初期化する必要があります。追加のブール変数/フラグがそのような変数ごとに割り当てられ、コントロールが宣言を通過するたびにチェックされることを達成するために。フラグが変数がまだ初期化されていないことを示している場合は、初期化されます。

  2. これらの静的変数には自明でないデストラクタがあるため、言語は、プログラム終了時の破棄順序が構築順序の逆であることを保証する必要があります。構築順序は実行時に決定されるため、プログラムは将来の破棄をスケジュールするために実行時の構造を準備する必要があります。これは、重要なデストラクタを持つ変数のステップ 1 の一部としても行われます。それらは、構築されたオブジェクトの「リスト」に構築順に登録されます。「リスト」は通常、事前に割り当てられた配列として実装されます (最大サイズはコンパイル時にわかっているため)。

  3. マルチスレッド構成では、上記の手順に追加のロック/ロック解除手順が伴う場合があります。

これらはすべて「内部」で実装される「家計」の費用であるため、実際のコストは実装に大きく依存する可能性があります。特定のコンパイラが生成するコードを参照/プロファイルします。

于 2012-07-10T14:20:10.113 に答える
1

static変数はプログラムの開始時に初期化されます。つまり、init は 1 回だけ発生します。ブール値だけのコストは非常に低く、あなたの場合はalternate1を実行するコストになりますがfoo()、これは単なる空の関数であるため、この例ではそれほど多くありません。

一般化すると、コストは、基本型 (int、float など) の初期化の最大コスト、またはユーザー定義型/ライブラリ定義型の初期化 (ctor の実行) のコストになります。関数staticで初期化されている場合、最大値は実行される関数のコストになります。

于 2012-07-10T13:48:58.047 に答える