wake-up-neo.com

Ist die statische Variable constexpr in einer Funktion sinnvoll?

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?

166
David Stone

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.

197
rici