関数内に変数 (たとえば、大きな配列) がある場合、static
と の両方を宣言するのは意味がありますかconstexpr
?はconstexpr
、配列がコンパイル時に作成されることを保証するので、 はstatic
役に立たないでしょうか?
void f() {
static constexpr int x [] = {
// a few thousand elements
};
// do something with the array
}
static
生成されたコードやセマンティクスに関して、実際に何かが行われていますか?
ベストアンサー1
簡単に答えると、それは役に立つだけでなくstatic
、常に求められるものになるということです。
まず、static
と はconstexpr
完全に独立していることに注意してください。static
は実行中のオブジェクトの存続期間を定義し、constexpr
コンパイル中にオブジェクトが使用可能であることを指定します。 コンパイルと実行は、時間的にも空間的にも分離され、不連続です。 したがって、プログラムがコンパイルされると、constexpr
は関係なくなります。
宣言されたすべての変数はconstexpr
暗黙的に ですconst
が、const
ほぼstatic
直交しています (整数との相互作用を除くstatic const
)。
オブジェクトC++
モデル (§1.9) では、ビット フィールド以外のすべてのオブジェクトが少なくとも 1 バイトのメモリを占有し、アドレスを持っていることが必要です。さらに、特定の時点でプログラム内で観察可能なすべてのそのようなオブジェクトは、異なるアドレスを持っている必要があります (パラグラフ 6)。これは、ローカルの非静的 const 配列を持つ関数の呼び出しごとに、コンパイラがスタック上に新しい配列を作成することを完全に要求するものではありません。なぜなら、コンパイラは、as-if
他のそのようなオブジェクトが観察されないことを証明できれば、この原則に頼ることができるからです。
残念ながら、関数が単純な場合 (たとえば、関数が翻訳単位内で本体が見えない他の関数を呼び出さない場合) を除いて、これを証明するのは簡単ではありません。配列は、多かれ少なかれ定義上、アドレスであるためです。そのため、ほとんどの場合、非静的const(expr)
配列は呼び出しごとにスタック上に再作成する必要があり、コンパイル時に計算できるという利点が失われます。
一方、ローカルstatic const
オブジェクトはすべてのオブザーバーによって共有され、さらに、それが定義されている関数が呼び出されなくても初期化される可能性があります。したがって、上記のいずれも適用されず、コンパイラはローカル オブジェクトのインスタンスを 1 つだけ生成できるだけでなく、読み取り専用ストレージにローカル オブジェクトのインスタンスを 1 つだけ生成することもできます。
したがって、static constexpr
例では必ず を使用する必要があります。
しかし、 を使いたくないケースが1つありますstatic constexpr
。constexpr
宣言されたオブジェクトが次のいずれかでない限り、ODR使用または が宣言されている場合static
、コンパイラはそれをまったく含めなくてもかまいません。これは、コンパイル時に一時配列を使用でき、コンパイルされたプログラムを不必要なバイトで汚染しないため、非常に便利です。その場合、は実行時にオブジェクトが存在するように強制する可能性が高いため、constexpr
を使用することは明らかに望ましくありません。static
static