2012-12-13 10 views
98

関数内に変数(例えば、大きな配列)がある場合、それをstaticconstexprの両方で宣言するのは意味がありますか? constexprはコンパイル時に配列が作成されることを保証しますので、staticは役に立たないでしょうか?静的なconstexpr変数は意味がありますか?

void f() { 
    static constexpr int x [] = { 
     // a few thousand elements 
    }; 
    // do something with the array 
} 

staticは、実際に生成されたコードや意味論の面でそこに何をしているのですか?

+11

'constexpr'はコンパイル時に何も保証しませんが、コンパイラは実行時に' constexpr'を評価することは自由です。コンパイル時に何かを評価しなければならないのは、コンパイル時に知っておく必要があるコンテキストで何かを使用すれば、それだけです。 – Praetorian

+0

私は@Praetorianが正しいと信じていて、 'static'はコンパイル時だけでなく、コンパイル時定数とともに格納されることを保証します。私は '静的'なしに、関数の呼び出しごとに(巨大な)配列をスタックにプッシュすることに理論的に合致すると思います。 –

+3

@AndrewLazarusは、理論的にはすべての呼び出し時にスタックに配列をプッシュすることに理論的に準拠しているだけでなく、理論的には必要です(as-ifルールをモジュロにします)。実際には、私の経験では、それは常によく起こります。詳細は私の答えを見てください。 – rici

答えて

120

短い答えは、staticが有用であるだけでなく、いつも望ましいことです。

最初に、staticconstexprは互いに完全に独立していることに注意してください。 staticは、実行中のオブジェクトの存続期間を定義します。 constexprは、コンパイル時にオブジェクトを使用できるように指定します。コンパイルと実行は時間と空間の両方で不連続で不連続です。したがって、プログラムがコンパイルされると、constexprはもはや関係しません。

すべての変数がconstexprを宣言し、暗黙的にconstですがconststaticstatic const整数との相互作用を除く。)はほぼ直交している

C++オブジェクトモデル(§ 1.9)は、ビットフィールド以外のすべてのオブジェクトが占めることが必要です少なくとも1バイトのメモリとアドレスを有する。さらに、与えられた瞬間にプログラム内で観測可能なすべてのオブジェクトは、別個のアドレスを持たなければならない(パラグラフ6)。これは、ローカル非静的const配列を持つ関数を呼び出すたびにスタック上に新しい配列を作成するコンパイラを必要としません。なぜなら、コンパイラはas-ifの原理で避けている可能性があるからです。観察される。

残念なことに、関数が自明でない限り(たとえば、翻訳単位内でボディが見えない他の関数を呼び出さない限り)、配列は多かれ少なかれ定義されているため、アドレスです。だから、ほとんどの場合、非静的配列はすべての呼び出し時にスタック上で再作成されなければならず、コンパイル時にそれを計算することができなくなります。

一方、ローカルのstatic constオブジェクトはすべてのオブザーバによって共有され、定義されている関数が呼び出されない場合でも初期化されます。したがって、上記のどれも適用されず、コンパイラーはそのインスタンスを1つだけ生成するだけでなく、読み取り専用ストレージでは、そのインスタンスを1つだけ生成することは自由です。

この例では、間違いなくstatic constexprを使用してください。

ただし、static constexperを使用しない場合があります。 constexpr宣言されたオブジェクトがODRが使用されているか、またはstaticと宣言されていない限り、コンパイラは自由にそれを含めません。これは、コンパイル時に不要なバイトを含むプログラムを汚染することなく、コンパイル時にconstexprの一時的な配列を使用できるので、非常に便利です。その場合、staticは実行時にオブジェクトを強制的に実行する可能性が高いため、明確にstaticを使用することは望ましくありません。

+1

コメントをしたとき、私はこれについて考えていました。 ISTM 'constexpr'は' const'とは異なり、常に読み込み専用の記憶領域に置くことができます(あなたは 'constexpr' [?]をキャストすることはできません)、それはスタック上に新しいコピーをプッシュする必要をなくします。 'const'変数のために必要となります。定数のリテラル文字列をプールするような並べ替え。しかし、それが合法かどうかは分かりません。 –

+1

@AndrewLazarusでは、 'const'オブジェクトから' const'をキャストすることはできません。 'const'は' X'を指します。しかしそれはポイントではありません。自動オブジェクトには静的アドレスを使用できないという点が重要です。私が言ったように、コンパイルが完了すると 'constexpr'は意味を持ちませんので、キャストする必要はありません(実行時にオブジェクトが存在することさえ保証されていないため、何もありません)。 – rici

+0

In C++ 1y、contexpr関数はconstではありません。 – refi64

関連する問題