web-dev-qa-db-fra.com

Les variables en ligne sont-elles uniques au-delà des limites?

Ceci est un suivi de cette question .
Comme mentionné dans les commentaires sur la réponse:

Une variable en ligne a la propriété que - Elle a la même adresse dans chaque unité de traduction. [...] En général, vous y êtes arrivé en définissant la variable dans un fichier cpp, mais avec le spécificateur inline, vous pouvez simplement déclarer/définir vos variables dans un fichier d'en-tête et chaque unité de traduction utilisant cette variable utilise exactement le même objet.

De plus, à partir de la réponse elle-même:

Bien que le langage ne garantisse pas (ni même ne mentionne) ce qui se passe lorsque vous utilisez cette nouvelle fonctionnalité au-delà des limites des bibliothèques partagées, cela fonctionne sur ma machine.

En d'autres termes, il n'est pas clair s'il est garanti qu'une variable en ligne est unique au-delà des limites lorsque des bibliothèques partagées sont impliquées. Quelqu'un a prouvé empiriquement que cela fonctionne sur certaines plates-formes, mais ce n'est pas vraiment une réponse et cela pourrait tout casser sur d'autres plates-formes.

Existe-t-il une garantie quant au caractère unique d'une variable en ligne lorsqu'elle est utilisée au-delà des limites ou s'agit-il simplement d'un détail d'implémentation sur lequel je ne devrais pas compter?

17
skypjack

Voici comment j'interprète la norme. Selon basic.link/1 :

Un programme consiste en une ou plusieurs unités de traduction liées entre elles.

Il ne dit rien sur les liens statiques ni les liens dynamiques. Un programme est une unité de traduction reliée entre elles. Peu importe que la liaison se fasse en deux étapes (commencez par créer un fichier .dll/.so, puis le linker dynamique lie toutes les bibliothèques dynamiques + exécutables ensemble).

Donc, dans mon interprétation, peu importe si un programme est lié dynamiquement ou statiquement, l'implémentation doit se comporter de la même manière: une variable statique de classe doit être unique (qu'elle soit en ligne ou non).

Sur Linux, c'est vrai.

Sous Windows, cela ne fonctionne pas dans toutes les circonstances. Par conséquent, selon mon interprétation, il enfreint la norme dans ces circonstances (si vous créez un fichier .dll distinct, qui contient la variable statique non inline, ainsi que tous les autres .dll et exe se réfère à cette variable, ça marche).

8
geza

C++ n'a actuellement pas de concept de bibliothèques partagées. Ainsi, le comportement de inline dans les bibliothèques partagées dépend de la mise en œuvre et de la plate-forme.

Le fait que [basic.link]/1 indique que "Un programme consiste en une ou plusieurs unités de traduction liées entre elles." Ne signifie pas tout à fait qu'un programme lié à un autre module déjà lié , devrait se comporter de la même manière.

Au fil des ans, de nombreuses propositions ont été soumises pour rectifier la situation ( N1400 , N1418 , N1496 , N1976 , N2407 , N3347 , N4028 ), dont aucun n'a décollé. C’est difficile d’implémenter de manière générique, et C++ essaie généralement de rester en dehors des détails d’implémentation. Comme GCC le mettre :

Pour les cibles qui ne prennent en charge ni COMDAT ni les symboles faibles, la plupart des entités avec un lien vague sont émises sous forme de symboles locaux afin d’éviter les erreurs de définition en double de l’éditeur de liens. Cela ne se produit toutefois pas pour les statistiques locales en ligne, car le fait de multiplier les copies casse certainement les choses.

MSVC n'expose aucun symbole par défaut. Tout symbole "externe" doit être explicitement déclaré avec un __declspec(dllexport)..__ spécifique à la plate-forme. On ne peut pas prétendre que Windows soit incompatible avec C++ pour cette raison. Aucune des règles C++ n'est violée ici, car il n'y en a pas.

4
rustyx

Existe-t-il une garantie quant au caractère unique d'une variable en ligne lorsqu'elle est utilisée au-delà des limites ou s'agit-il simplement d'un détail d'implémentation sur lequel je ne devrais pas compter?

C'est à vous de vous en assurer (en vous assurant que toutes les déclarations sont en fait les mêmes).

Le compilateur ne peut évidemment pas vérifier cela et l'éditeur de liens ne s'en préoccupe pas. Donc, si vous mentez à l’éditeur de liens (en pas à faire ce qui précède), vous finirez par avoir des ennuis.


OK, puisque tout le monde ne comprend pas ce que je veux dire par «mentir à l'éditeur de liens», je vais l'expliquer un peu.

@oliv aimablement fourni ce lien , qui dit entre autres ce qui suit (le mien de commentaire):

Copies en double de ces constructions [i.e. les variables déclarent inline dans plusieurs TU] seront ignorées au moment de la liaison.

Ce qui est bien, c'est ce dont nous avons besoin. La chose est, vous ne savez pas lequel (évidemment, un seul est retenu, donc, par extension, vous ne savez pas lequel sera).

Donc, s'ils diffèrent, vous ne savez pas avec qui vous allez vous retrouver et vous obtenez donc une forme particulièrement insidieuse de UB. C'est ce que je voulais dire par «mentir à l'éditeur de liens». Parce que, en déclarant vos variables différemment dans différentes TU, c'est exactement ce que vous avez fait. Oups!

1
Paul Sanders