Utilisation de static et inline en C++

Les fonctions et variables membres hors classe

  • Les fonctions ou varibales marquées inline (privilège introduit en C++17 pour les variables) sont stockées globalement dans une seule instance ;
  • Les éléments marqués static sont chacun copiés dans chaque unité de compilation ;
  • Les variables statiques locales dans des fonctions static ont plusieurs copies, tandis que celles dans des fonctions inline n'en ont qu'une seule ;
  • Une déclaration combinée static inline a le même effet qu’un simple static ;
  • Le mot-clé inline ne peut pas être utilisé sur des variables locales.

Les membres fonctionnels et variables au sein d'une classe

  • Depuis C++17, les variables statiques non constantes peuvent être initialisées directement à l'intérieur de la déclaration de la classe grâce à static inline. Avant C++17, cette initialisation devait obligatoirement se faire en dehors de la classe ;
  • En C++17, si une variable statique de classe est déclarée avec static inline, son initialisation en tête de fichier (dans un .h) ne provoque plus d'erreur de redéfinition. Sans inline, cela entraîne une duplication entre les unités de compilation, causant des erreurs liées au lien ;
  • Avant C++17, toute initialisation d'une variable statique de classe dans un fichier d'en-tête conduisait à une erreur de redéfinition. Il fallait donc la placer dans un fichier source (.cpp) pour éviter ce problème ;
  • En réalité, toutes les fonctions membres d'une classe sont implicitement traitées comme inline, car elles sont définies globalement une seule fois. La présence ou non de static ne change pas leur localisation, mais seulement leur accès aux membres : les fonctions static n'accèdent qu'aux membres statiques, tandis que les fonctions normales peuvent accéder à tous les membres.

Pourquoi les variables statiques non constantes étaient-elles interdites en initialisation directe dans la classe avant C++17 ?

  • Les variables statiques appartiennent à la classe, pas à une instance. Si elles étaient initialisées directement dans la définition de la classe, chaque objet construit aurait réinitialisé cette variable, entraînant des comportements imprévisibles ;
  • Les variables statiques constantes, quant à elles, pouvaient être initialisées à l’intérieur de la classe car elles ne changent jamais après leur construction — leur valeur est figée dès la compilation ;
  • Avant C++17, il était strictement interdit d’initialiser une variable statique non constante dans la déclaration de la classe. Toute tentative d’initialisation dans un fichier d’en-tête provoquait une erreur de redéfinition lors du lien ;
  • Avec C++17, l’introduction de inline pour les membres statiques permet d’assurer qu’une seule copie existe globalement. Grâce à cette sémantique, une variable statique peut être déclarée et intiialisée directement dans la classe, ou déclarée dans la classe et initialisée via inline dans un fichier d’en-tête. Cela garantit une initialisation unique et partagée.

Exemple concret illustratif

Phase 1

main.cpp

#include "test.h"
#include "test2.h"

int main() {
    return 0;
}

test.h

bool flag = true;

test2.h

#include "test.h"

Résultat de la compilation :

Erreur C2374 : « flag » redéfini ; initialisation multiple

Phase 2

Modification de test.h :

#pragma once
bool flag = true;

Résultat du lien :

Erreur LNK2005 : « bool flag » déjà définie dans test.obj

Phase 3

Modification de test.h :

#pragma once
inline bool flag = true;

Résultat :

Génération réussie : 1 succès, 0 échecs

Ce cas montre clairement un usage typique des variables inline : éviter les conflits de redéfinition dans les fichiers d’en-tête.

On peut aussi déplacer la définition dans un fichier .cpp, ce qui aurait eu le même effet positif.

Étiquettes: static inline C++17 variable globale liaison

Publié le 1 septembre à 14h38