web-dev-qa-db-fra.com

La variable statique constexpr dans une fonction a-t-elle un sens?

Si j'ai une variable dans une fonction (disons un grand tableau), est-il judicieux de la déclarer à la fois static et constexpr? constexpr garantit que le tableau est créé au moment de la compilation, alors le static serait-il inutile?

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

La static fait-elle réellement quelque chose en termes de code généré ou de sémantique?

166
David Stone

La réponse courte est que non seulement static est utile, il est pratiquement toujours souhaitable.

Tout d'abord, notez que static et constexpr sont complètement indépendants l'un de l'autre. static définit la durée de vie de l'objet pendant son exécution; constexpr spécifie que l'objet doit être disponible lors de la compilation. La compilation et l'exécution sont disjointes et discontinues, à la fois dans le temps et dans l'espace. Donc, une fois le programme compilé, constexpr n'est plus pertinent.

Toute variable déclarée constexpr est implicitement const mais const et static sont presque orthogonales (sauf pour l'interaction avec static const entiers.)

Le modèle d'objet C++ (§1.9) requiert que tous les objets autres que les champs de bits occupent au moins un octet de mémoire et aient des adresses. de plus, tous les objets observables dans un programme à un moment donné doivent avoir des adresses distinctes (paragraphe 6). Cela n’impose pas au compilateur de créer un nouveau tableau sur la pile pour chaque appel d’une fonction avec un tableau local non statique, car le compilateur pourrait se réfugier dans le principe as-if à condition de prouver autre tel objet peut être observé.

Malheureusement, cela ne sera pas facile à prouver sauf si la fonction est triviale (par exemple, elle n'appelle aucune autre fonction dont le corps n'est pas visible dans l'unité de traduction) car les tableaux, plus ou moins par définition, sont des adresses. Ainsi, dans la plupart des cas, le tableau non statique const(expr) devra être recréé sur la pile à chaque appel, ce qui annule le point de pouvoir le calculer au moment de la compilation.

D'autre part, un objet local static const est partagé par tous les observateurs et peut en outre être initialisé même si la fonction dans laquelle il est défini n'est jamais appelée. Donc, rien de ce qui précède ne s’applique, et un compilateur est libre non seulement de générer une seule instance de celui-ci; il est libre d'en générer une seule instance dans un stockage en lecture seule.

Vous devez donc absolument utiliser static constexpr dans votre exemple.

Cependant, il existe un cas où vous ne voudriez pas utiliser static constexpr. À moins qu'un objet déclaré constexpr soit ODR-used ou déclaré static, le compilateur est libre de ne pas l'inclure du tout. C'est très utile, car cela permet d'utiliser des tableaux temporaires constexpr au moment de la compilation sans polluer le programme compilé avec des octets inutiles. Dans ce cas, vous ne voudrez évidemment pas utiliser static, car static est susceptible de forcer l'objet à exister au moment de l'exécution.

197
rici