C++17 inline
variables
Cette fonctionnalité géniale de C++17 nous permet de :
- utiliser commodément une seule adresse mémoire pour chaque constante
- le stocker comme un
constexpr
: Comment déclarer constexpr extern ?
- le faire en une seule ligne à partir d'un seul en-tête
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(¬main_i == notmain_func());
assert(notmain_i == 42);
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return ¬main_i;
}
Compilez et exécutez :
g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main
GitHub en amont .
Voir aussi : Comment fonctionnent les variables en ligne ?
Norme C++ sur les variables en ligne
La norme C++ garantit que les adresses seront les mêmes. Projet de norme C++17 N4659 10.1.6 "Le spécificateur en ligne" :
6 Une fonction en ligne ou une variable avec lien externe doit avoir la même adresse dans toutes les unités de traduction.
Référence cpp https://en.cppreference.com/w/cpp/language/inline explique que si static
n'est pas donné, alors il a un lien externe.
Mise en œuvre des variables en ligne
Nous pouvons observer comment il est mis en œuvre avec :
nm main.o notmain.o
qui contient :
main.o:
U _GLOBAL_OFFSET_TABLE_
U _Z12notmain_funcv
0000000000000028 r _ZZ4mainE19__PRETTY_FUNCTION__
U __assert_fail
0000000000000000 T main
0000000000000000 u notmain_i
notmain.o:
0000000000000000 T _Z12notmain_funcv
0000000000000000 u notmain_i
et man nm
dit à propos de u
:
"u" Le symbole est un symbole mondial unique. Il s'agit d'une extension GNU de l'ensemble standard des liaisons de symboles ELF. Pour un tel symbole, l'éditeur de liens dynamiques s'assurera que dans tout le processus il n'y ait qu'un seul symbole de ce nom et de ce type utilisé.
nous voyons donc qu'il y a une extension ELF dédiée pour cela.
Projet de norme C++17 sur le terme "global". const
implique static
C'est la citation de ce qui a été mentionné à : https://stackoverflow.com/a/12043198/895245
Projet de norme C++17 n4659 6.5 "Programme et lien" :
3 Un nom ayant la portée d'un espace de nom (6.3.6) a un lien interne s'il est le nom de
- (3.1) - une variable, une fonction ou un modèle de fonction qui est explicitement déclaré statique ; ou,
- (3.2) - une variable non en ligne de type qualifié const non volatile qui n'est ni explicitement déclarée extern ni déclarée précédemment comme ayant un lien externe ; ou
- (3.3) - une donnée membre d'une union anonyme.
La portée de l'"espace de noms" est ce que nous appelons familièrement "global".
Annexe C (informative) Compatibilité, C.1.2 La clause 6 : "concepts de base" donne la raison pour laquelle cela a été changé de C :
6.5 [également 10.1.7]
Le changement : Un nom de fichier qui est explicitement déclaré const, et non explicitement déclaré extern, a un lien interne, alors qu'en C, il aurait un lien externe. interne, alors qu'en C il aurait un lien externe.
Justification : Étant donné que les objets const peuvent être utilisés comme valeurs lors de la traduction en C++, cette fonctionnalité incite les programmeurs à fournir des informations sur les valeurs. les programmeurs à fournir un initialisateur explicite pour chaque objet const. Cette fonctionnalité permet à l'utilisateur de mettre des objets const dans des fichiers sources qui sont inclus dans plusieurs unités de traduction.
Effet sur la caractéristique originale : Modification de la sémantique d'une caractéristique bien définie.
Difficulté de la conversion : Transformation sémantique.
Largement utilisé : Rarement.
Voir aussi : Pourquoi const implique-t-il un lien interne en C++, alors que ce n'est pas le cas en C ?
Testé dans GCC 7.4.0, Ubuntu 18.04.