Если у меня есть переменная внутри функции (скажем, большой массив), имеет ли смысл объявить ее обе static
а также constexpr
? constexpr
гарантирует, что массив создается во время компиляции, так что static
быть бесполезным?
void f() {
static constexpr int x [] = {
// a few thousand elements
};
// do something with the array
}
Это static
на самом деле делать что-то там с точки зрения сгенерированного кода или семантики?
Короткий ответ: не только static
полезно, это очень хорошо всегда будет желать лучшего.
Во-первых, обратите внимание, что static
а также constexpr
полностью независимы друг от друга. static
определяет время жизни объекта во время выполнения; constexpr
указывает, что объект должен быть доступен во время компиляции. Компиляция и исполнение являются несвязанными и несмежными как во времени, так и в пространстве. Итак, когда программа скомпилирована, constexpr
больше не актуально.
Каждая переменная объявлена constexpr
неявно const
но const
а также static
почти ортогональны (за исключением взаимодействия с static const
целые числа.)
C++
объектная модель (§1.9) требует, чтобы все объекты, кроме битовых полей, занимали хотя бы один байт памяти и имели адреса; кроме того, все такие объекты, наблюдаемые в программе в данный момент, должны иметь разные адреса (пункт 6). Это совсем не требует, чтобы компилятор создавал новый массив в стеке для каждого вызова функции с локальным нестатическим константным массивом, потому что компилятор мог найти убежище в as-if
принцип при условии, что это может доказать, что никакой другой такой объект не может быть соблюден.
К сожалению, доказать это будет непросто, если только функция не является тривиальной (например, она не вызывает никакой другой функции, тело которой не видно внутри единицы преобразования), поскольку массивы, более или менее по определению, являются адресами. Так что в большинстве случаев нестатический const(expr)
При каждом вызове массив должен быть воссоздан в стеке, что лишает его возможности вычислять его во время компиляции.
С другой стороны, местный static const
Объект является общим для всех наблюдателей, и, кроме того, он может быть инициализирован, даже если функция, в которой он определен, никогда не вызывается. Таким образом, ничего из вышеперечисленного не применимо, и компилятор может не только генерировать только один его экземпляр; он может генерировать один экземпляр в хранилище только для чтения.
Так что вы обязательно должны использовать static constexpr
в вашем примере.
Однако есть один случай, когда вы не захотите использовать static constexpr
, Если только constexpr
объявленный объект либо ODR используемый или объявлено static
, компилятор может не включать его вообще. Это довольно полезно, потому что позволяет использовать временную компиляцию constexpr
массивы без загрязнения скомпилированной программы ненужными байтами. В этом случае вы бы явно не хотели использовать static
, поскольку static
может заставить объект существовать во время выполнения.
Других решений пока нет …