Имеет ли смысл статическая переменная constexpr?


если у меня есть переменная внутри функции (скажем, большой массив), имеет ли смысл объявлять ее как static и constexpr? constexpr гарантии, что массив создается во время компиляции, так static бесполезно?

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

- это static на самом деле делать что-нибудь там с точки зрения сгенерированного кода или семантики?

1 126

1 ответ:

короткий ответ заключается в том, что не только static полезно, это довольно хорошо всегда будет желанным.

во-первых, обратите внимание, что static и constexpr полностью независимы друг от друга. static определяет время жизни объекта во время выполнения;constexpr указывает, что объект должен быть доступен во время компиляции. Компиляция и выполнение являются непересекающимися и несвязными, как во времени, так и в пространстве. Поэтому, как только программа будет скомпилирована,constexpr больше не соответствующий.

каждая переменная, объявленная constexpr неявно const но const и static почти ортогональны (за исключением взаимодействия с static const целых чисел.)

The C++ объектная модель (§1.9) требует, чтобы все объекты, отличные от битовых полей, занимали по крайней мере один байт памяти и имели адреса; кроме того, все такие объекты, наблюдаемые в программе в данный момент, должны иметь различные адреса (пункт 6). Это не совсем требует компилятора чтобы создать новый массив в стеке для каждого вызова функции с локальным нестатическим массивом const, потому что компилятор может укрыться в as-if принцип при условии, что он может доказать, что никакой другой такой объект не может наблюдаться.

это будет нелегко доказать, к сожалению, если функция не является тривиальной (например, она не вызывает никакой другой функции, тело которой не видно в единице перевода), потому что массивы, более или менее по определению, являются адреса. Так что в большинстве случаев, нестатические const(expr) массив должен быть воссоздан в стеке при каждом вызове, что не позволяет вычислить его во время компиляции.

С другой стороны, местный static const объект является общим для всех наблюдателей, и, кроме того, может быть инициализирован, даже если функция, в которой он определен, никогда не вызывается. Таким образом, ничто из вышеперечисленного не применяется, и компилятор свободен не только генерировать только один экземпляр; он свободен генерировать один экземпляр его в хранилище только для чтения.

так что вы обязательно должны использовать static constexpr в вашем примере.

однако, есть один случай, когда вы не хотели бы использовать static constexpr. Если constexpr объявленный объект либо ODR-используется или объявлены static, компилятор может не включать его вообще. Это довольно полезно, потому что это позволяет использовать время компиляции temporary constexpr массивы без загрязнения скомпилированной программы ненужными байты. В этом случае вы явно не захотите использовать static с static вероятно, чтобы заставить объект существовать во время выполнения.