1. ホーム
  2. c++

[解決済み】関数内の静的constexpr変数は意味があるのでしょうか?

2022-04-03 21:52:33

質問

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

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

static 生成されたコードやセマンティクスに関して、実際にそこで何かを行っているのでしょうか?

どのように解決するのですか?

簡単に言うと static は有用であり、常に必要とされるものです。

まず、以下の点に注意してください。 staticconstexpr は互いに完全に独立しています。 static は、実行中のオブジェクトの寿命を定義します。 constexpr は、コンパイル時にオブジェクトが利用可能であることを指定します。コンパイルと実行は、時間的にも空間的にも不連続であり、不連続です。ですから、プログラムがコンパイルされると constexpr はもう関係ない。

を宣言したすべての変数が constexpr は暗黙のうちに const しかし conststatic との相互作用を除けば)ほぼ直交しています。 static const 整数)

は、その C++ オブジェクトモデル (§1.9) は、ビットフィールド以外のすべてのオブジェクトが少なくとも1バイトのメモリを占め、アドレスを持つことを要求します。さらに、ある瞬間にプログラム内で観測可能なそのようなオブジェクトはすべて明確なアドレスを持たなければなりません (段落 6)。このことは、ローカルで非静的な定数配列を持つ関数を呼び出すたびに、コンパイラがスタック上に新しい配列を作成することを要求しているわけではありません。 as-if このようなオブジェクトが他に観測されないことを証明できるのであれば、この原則は適用されません。

配列は多かれ少なかれアドレスであるため、その関数が些細なものでない限り(例えば、翻訳ユニット内で本体が見えない他の関数を呼び出さないなど)、残念ながらそれを証明するのは簡単ではなさそうです。ですから,ほとんどの場合,非静的な const(expr) 配列は起動のたびにスタック上に再作成する必要があり、コンパイル時に計算できることの意味がなくなります。

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

だから、絶対に static constexpr を使用します。

しかし、1つだけ使用したくないケースがあります。 static constexpr . ただし constexpr 宣言されたオブジェクトは ODR-使用 または宣言された static の場合、コンパイラはそれを全く含まないという自由があります。これは非常に便利なことで、コンパイル時の一時的な constexpr の配列は、コンパイルされたプログラムを不要なバイトで汚染することはありません。このような場合、明らかに static というのは static は、実行時にそのオブジェクトを強制的に存在させる可能性があります。