Wenn ich eine Variable in einer Funktion habe (z. B. ein großes Array), ist es sinnvoll, sie sowohl als static
als auch als constexpr
zu deklarieren? constexpr
garantiert, dass das Array zur Kompilierungszeit erstellt wird. Wäre das static
also nutzlos?
void f() {
static constexpr int x [] = {
// a few thousand elements
};
// do something with the array
}
Tut das static
tatsächlich etwas in Bezug auf generierten Code oder Semantik?
Die kurze Antwort ist, dass nicht nur static
nützlich ist, es wird auch immer erwünscht sein.
Beachten Sie zunächst, dass static
und constexpr
völlig unabhängig voneinander sind. static
definiert die Lebensdauer des Objekts während der Ausführung. constexpr
gibt an, dass das Objekt während der Kompilierung verfügbar sein soll. Zusammenstellung und Ausführung sind zeitlich und räumlich unzusammenhängend und unzusammenhängend. Sobald das Programm kompiliert ist, ist constexpr
nicht mehr relevant.
Jede als constexpr
deklarierte Variable ist implizit const
, aber const
und static
sind fast orthogonal (mit Ausnahme der Interaktion mit static const
- Ganzzahlen).
Das Objektmodell C++
(§1.9) erfordert, dass alle Objekte außer Bitfeldern mindestens ein Byte Speicher belegen und Adressen haben; Darüber hinaus müssen alle in einem Programm zu einem bestimmten Zeitpunkt beobachtbaren Objekte unterschiedliche Adressen haben (Absatz 6). Dies erfordert nicht unbedingt, dass der Compiler für jeden Aufruf einer Funktion mit einem lokalen nicht statischen const-Array ein neues Array auf dem Stack erstellt, da der Compiler das as-if
- Prinzip anwenden könnte, sofern er dies nachweisen kann Kein anderer solcher Gegenstand kann beobachtet werden.
Das wird leider nicht einfach zu beweisen sein, es sei denn, die Funktion ist trivial (zum Beispiel ruft sie keine andere Funktion auf, deren Hauptteil in der Übersetzungseinheit nicht sichtbar ist), da Arrays mehr oder weniger per Definition Adressen sind. In den meisten Fällen muss das nicht-statische Array const(expr)
bei jedem Aufruf auf dem Stack neu erstellt werden, was den Punkt zunichte macht, dass es zur Kompilierungszeit berechnet werden kann.
Andererseits wird ein lokales static const
- Objekt von allen Beobachtern gemeinsam genutzt und kann auch dann initialisiert werden, wenn die Funktion, in der es definiert ist, niemals aufgerufen wird. Daher gilt keines der oben genannten Punkte, und es steht einem Compiler frei, nicht nur eine einzelne Instanz davon zu generieren. Es ist kostenlos, eine einzelne Instanz davon im Nur-Lese-Speicher zu generieren.
Verwenden Sie in Ihrem Beispiel also unbedingt static constexpr
.
Es gibt jedoch einen Fall, in dem Sie static constexpr
Nicht verwenden möchten. Sofern ein constexpr
deklariertes Objekt nicht ODR-used oder static
deklariert ist, kann der Compiler es überhaupt nicht einschließen. Das ist ziemlich nützlich, da es die Verwendung von temporären constexpr
Arrays zur Kompilierungszeit erlaubt, ohne das kompilierte Programm mit unnötigen Bytes zu belasten. In diesem Fall möchten Sie natürlich nicht static
verwenden, da static
das Objekt wahrscheinlich zur Laufzeit existieren lässt.