One Definition Rule (ODR) — c'est une règle fondamentale en C++ qui exige qu'il y ait une seule définition pour chaque objet, fonction ou classe dans l'ensemble de la programme (tous les modules de traduction).
L'ODR est violée si :
Cela entraîne des bugs difficiles à détecter et imprévisibles, une mauvaise liaison ou, ce qui est pire, un comportement variable de l'application en fonction de la manière dont elle a été assemblée.
Pourquoi les violations se produisent :
Dans les grands projets, il est fréquent de copier/modifier des fichiers .h sans contrôle de version, ou de séparer le code en plusieurs modules avec compilation distincte. Si quelqu'un change une fonction inline seulement à un endroit, les autres fichiers source peuvent avoir une ancienne version.
Comment éviter :
constexpr ou, avec C++17, des variables inline.Peut-on définir des fonctions statiques (static void foo()) avec le même nom et des implémentations différentes dans différents fichiers .cpp sans conséquences ?
Beaucoup pensent que les fonctions statiques n'ont aucun impact l'une sur l'autre entre les modules. La réponse : oui, c'est possible, car chacune d'elles a un linkage interne (visible uniquement dans son module de traduction). Cependant, cela n'est pas garanti pour les fonctions inline et les modèles, ce qui est souvent confondu.
Exemple :
// file1.cpp static void foo() { std::cout << "A"; } // file2.cpp static void foo() { std::cout << "B"; }
Les appels dans ces modules seront indépendants.
Histoire
Dans un grand projet, un développeur a modifié le corps d'une fonction inline uniquement dans l'un des clones du fichier .h. Après la compilation, un certain comportement est devenu imprévisible : une partie des modules fonctionnait selon l'ancienne logique, tandis que l'autre utilisait la nouvelle. La raison : une violation de l'ODR pour la fonction inline.
Histoire
Lors de la migration vers C++17, une variable constante était définie dans plusieurs fichiers d'en-tête sans utiliser le mot clé inline. Un grand nombre d'erreurs de symbole dupliqué sont apparues lors de la liaison. Cela a été corrigé en déclarant la variable comme
inline const.
Histoire
Il a été découvert tardivement que le fichier .h généré du système de construction contenait deux implémentations de la même méthode de classe modèle, différant par un seul test ifdef dans différentes compilations. Plus tard, l'application plantait périodiquement en raison d'un désaccord sur l'ABI entre les modules liés.