2

プログラムの一部のファイルの上部、すべての関数の外に、次の変数があります。

namespace {
  int foo = foo_func();
}

int bar = bar_func();

ご存知のように、fooはそのファイルに対してのみローカルな変数ですが、barすべてのファイルにアクセスできます。

...しかし質問:関数はいつ実際に実行されますかfoo_func()bar_func()これは実行前に発生しますかmain()、それとも後で(たとえば、これらの値が実際に必要になる直前に)発生しますか?

4

2 に答える 2

4

言語仕様では、初期化関数は、その変換ユニットからの関数が呼び出される前、またはその変換ユニットで定義されたオブジェクトにアクセスされる前に実行される規定されています。したがって、一般的なケースでは、定義が翻訳単位全体にどのように分散しているかによって異なります。

初期化は上から下の順序で実行されるため、定義の順序を指定すると、bar_funcすでに初期化されていることfooがわかりますが、foo_func「初期化されていない」(つまり、ゼロで初期化されている)と表示されbarます。

main別の翻訳ユニットに常駐している場合は、の前に初期化を行う必要がないことに注意してくださいmain()fooただし、アクセスまたはアクセス(または他の場所barから)を試みる場合はmain、これらの変数を定義した変換ユニット全体に対して初期化プロセスがトリガーされることが保証されます。

また、初期化子が定数式(constexpr関数)の場合、初期化全体を静的に実行できます。これは通常、変数が既に初期化された(コンパイル時に初期化された)状態で存続期間を開始することを意味します。

于 2013-01-18T20:27:31.143 に答える
4

非関数からの戻り値で初期化するのconstexprは動的初期化です。動的初期化の順序は次のように定義されます(あなたの質問とは無関係だと思う詳細をいくつか省略します)。

§3.6.2/2:

静的ストレージ期間(3.7.1)またはスレッドストレージ期間(3.7.2)の変数は、他の初期化が行われる前にゼロ初期化(8.5)される必要があります。

[...]

単一の変換ユニット内で定義された順序付き初期化を持つ変数は、変換ユニット内で定義された順序で初期化されるものとします。プログラムがスレッド(30.3)を開始した場合、変数の後続の初期化は、別の変換単位で定義された変数の初期化に関して順序付けられません。それ以外の場合、変数の初期化は、別の変換単位で定義された変数の初期化に関して不確定に順序付けられます。

§3.6.2/3:

実装は、静的初期化として静的ストレージ期間を持つ非ローカル変数の初期化を実行できます。ただし、そのような初期化を静的に行う必要がない場合でも、[Jerryの要約:それが動的に行われます。]

§3.6.2/4:

mainの最初のステートメントの前に、静的ストレージ期間を持つ非ローカル変数の動的初期化を実行するかどうかは、実装によって定義されます。mainの最初のステートメントの後のある時点まで初期化が延期される場合、初期化される変数と同じ変換単位で定義された関数または変数の最初のodr-use(3.2)の前に発生するものとします。

于 2013-01-18T20:32:06.517 に答える