|
Publicité ' | |||||||||||||||||||||||
|
|
#1 | ||||
|
Nouveau Membre du Club
![]() Camille GillotÉtudiant Inscription : septembre 2007 Messages : 47 ![]() |
Bonjour,
J'ai une classe template A qui contient un champ de données membre statique x. Y-a-t'il un moyen de s'assurer que A<T>:: x va être réellement instancié (ie. symbole créé dans le fichier objet), pour toute instantiation implicite de A. On garantit qu'un objet de type A<T> est créé. Exemple : Code :
Code :
Avec-vous une quelconque idée ? Cordialement, Camille |
||||
|
|
00
|
|
|
#2 | ||
![]() ![]() |
Salut,
Il est vrai que je viens de passer plusieurs heures sur une réponse et que je dois donc tout doucement commencer à fatiguer, mais... A moins que je n'ai vraiment pas les yeux en face des trous, il n'y a aucun membre statique dans ta structure ![]() Erreur de copier / coller, ou oubli réel dans ton code Pour déclarer un membre statique dans une structure, il faut utiliser le mot clé static, sous une forme proche de Code :
Note toutefois que static implique que le membre est "global" dans l'unité de compilation dans laquelle il se trouve. Il n'est donc pas forcément impossible que, pou un T donné, tu te retrouves au final avec plusieurs A<T>: Note aussi que, ne le rendant pas privé dans le cas présent, tu t'expose à ce que "tout et n'importe quoi", y compris les fonctions qui ne disposent pas d'un objet de type A<T>, aille en modifier la valeur à "n'importe quel moment"... Ce n'es clairement pas une situation idéale car au final, cela se rapproche très fort d'une variable globale, et tu sais ce qu'on en pense généralement Peut etre devrais tu revoir ce point pour t'éviter quelques déboires
__________________
en bas de page
|
||
|
|
00
|
|
|
#3 |
|
Nouveau Membre du Club
![]() Camille GillotÉtudiant Inscription : septembre 2007 Messages : 47 ![]() |
Désolé, pour le static, c'est juste une erreur de copier-coller.
De même, le "template<...> unsigned A<T>:: x" devrait se trouver dans a.tpp. Je connais les risques associés aux globales ; le but réel serait de créer une sorte de constante de classe dépendant de T, calculée dans a.cpp ; puis lue dans un b.cpp, qui n'a accès qu'à la déclaration de la classe A<T>. |
|
|
00
|
|
|
#4 | ||||||||
![]() ![]() |
A ce moment là, tu ferais beaucoup mieux d'encapsuler un tout petit peu A<T>:: x, de manière à ce qu'il ne soit effectivement utilisé que dans a.tpp.
Si tu le rend constant, cela n'aura pas beaucoup d'importance, mais, à moins qu'il ne s'agisse aussi d'une erreur de copier/coller, A<T>:: x n'est pas constant, et donc, susceptible de changer à beaucoup d'endroit. Avec un x constant, tu peux sans problème laisser l'initialisation dans a.hpp et ne pas trop t'en faire pour l'encapsulation, sous une forme proche de a.hpp Code :
Par contre, si A<T>:: x n'est pas constant, il faut veiller à ce que son utilisation ne sorte pas de l'unité de compilation dans laquelle il est effectivement utilisé ![]() Tu pourrais, par exemple, le faire passer dans l'accessibilité privée et rendre une fonction amie, pour qu'elle puisse en profiter, sous une forme proche de a.hpp Code :
Code :
Code :
__________________
en bas de page
|
||||||||
|
|
00
|
|
|
#5 |
|
Nouveau Membre du Club
![]() Camille GillotÉtudiant Inscription : septembre 2007 Messages : 47 ![]() |
Merci pour les conseils, mais tu t'attaches à l'encapsulation, qui n'est pas du tout le problème ici.
La question est en fait : étant donné un type T fixe, quel code faut-il écrire dans a.cpp pour que le symbole A<T>:: x soit accessible depuis b.cpp qui n'inclut pas la définition de A<T>:: x ? Après, peu importe qui accède, ou comment, du moment que le symbole est généré. Dans le cas général, je sais qu'une instantiation explicite suffit. Mais si je me restreins à une instantiation implicite et un appel de fonction membre ? C'est une question théorique sur l'instantiation template en fait. |
|
|
00
|
|
|
#6 |
![]() ![]() |
Ce que tu ne sembles pas comprendre, c'est que toute la différence tient dans le fait que x est constant ou non...
Si c'est "simplement" une constante pure et dure, tu peux sans problème la définir dans ton fichier d'en-tête, car elle sera construite pour chaque implémentation de A<T> que tu pourras faire, dans chaque unité de compilation qui en a besoin, et l'on peut très bien se "foutre éperdument" du fait que cette constante se trouve dans XXX fichiers objet : si elle s'y trouve, c'est que chaque fichier objet utilise une instanciation de A<T> et qu'il en avait donc besoin. Par contre, si x n'est pas une constante (et c'est ce que montre ton code, à moins qu'il ne s'agisse d'une erreur de copier coller !!!), alors, il faut savoir que cette variable a une valeur qui est propre à l'unité de compilation qui l'utilise. Tu pourrais très bien en arriver à une situation pour le moins dangereuse où Truc.cpp qui instancie A<Truc> se trouve occupé à utiliser A<Truc>:: x avec un valeur de 12, alors que Machin.cpp utilise lui aussi A<Truc> mais dans lequel A<Truc>:: x a une valeur de 126 C'est une situation pour le moins fragile, tu en conviendras C'est la raison pour laquelle j'attire ton attention sur le fait qu'il faut savoir exactement ce que tu attends de A<T>:: x et sur les options qui s'offrent à toi C'est d'autant plus vrai que si Truc.cpp instancie A<Truc>, tu cours le risque (selon l'ordre dans d'appel de tes fonctions) qu'une fonction machin qui se trouve dans Machin.cpp essaye d'accéder à A<Truc>:: x alors que la variable n'a pas encore été créée
__________________
en bas de page
|
|
|
00
|
|
|
#7 | ||
|
Nouveau Membre du Club
![]() Camille GillotÉtudiant Inscription : septembre 2007 Messages : 47 ![]() |
Il est parfaitement légal d'écrire :
Code :
Si tu veux savoir, le calcul de A<>:: x requiert plusieurs centaines de lignes de templates pour obtenir une constante de compilation. Ce n'est pas parce que je donne un code rudimentaire sans encapsulation que je ne sais pas l'utiliser, c'est simplement que c'est hors propos de la question. Je le répète : c'est une question théorique sur les templates. |
||
|
|
00
|
|
|
#8 | |||||||||||||
![]() ![]() |
Citation:
Cela pourrait prendre la forme de Code :
Citation:
Tu as corrigé une partie de mes interrogation (en confirmant que x était bien statique), ce n'est que maintenant que tu me confirme qu'il s'agit d'une constante de compilation. Avant d'en arriver à ce point de la discussion, il m'était impossible de le savoir (alors que je te l'ai demandé trois fois). J'ai donc veillé à chaque fois travailler selon les deux hypothèses, tout simplement Evidemment, il y a toujours une hypothèse qui attire plus l'attention qu'une autre, entre autres, parce qu'elle requière des explications plus longues. Je n'y peux pas grand chose si tu as choisi de te braquer à chaque fois sur ces explications là alors que, comme tu le dis, c'est hors de propos. Citation:
Oui, il est tout à fait valide de définir une variable statique d'une classe template dans un .cpp ou dans un tpp. Seulement, si tu le fais, tu n'as qu'une seule garantie quant à l'initialisation de cette variable : en dehors du .cpp dans lequel la valeur est définie ou de tout cpp qui inclut aussi le tpp, tu n'as aucune garantie que la variable aura bel et bien été initialisée. C'est à dire que si tu découpes ton code sous une forme proche de a.hpp Code :
Code :
Code :
Code :
Si tu essayes d'accéder à cette valeur depuis ta fonction bar, tu auras peut etre de la chance... ou pas... Avec un peu de chance, selon l'ordre dans lequel l'éditeur de liens aura travaillé, A<Machin>:: x aura été défini, et tu pourra l'utiliser Avec un peu moins de chance, ce ne sera pas le cas, et tu te retrouveras avec des résultats aberrants. C'est la raison pour laquelle je te conseillerais plutot de passer par une énumération, car tu sera sur que cette constante de compilation est correctement définie
__________________
en bas de page
|
|||||||||||||
|
|
00
|
|
|
#9 | ||||||||||||||
|
Nouveau Membre du Club
![]() Camille GillotÉtudiant Inscription : septembre 2007 Messages : 47 ![]() |
Citation:
Citation:
Citation:
Citation:
Maintenant : existe-t-il un moyen pour garantir le cas que tu appelles "chance" ? Le standard spécifie que ça fonctionne (ie. la définition de x est instanciée) si x est référencé dans le code de a.cpp. Mon premier post donne une tentative, mais qui se trouve invalidée par l'optimisation. Connais-tu un moyen pour ça ? |
||||||||||||||
|
|
00
|
|
|
#10 | |||||
![]() ![]() |
Citation:
Et comme tu me dis qu'il faut une centaine de ligne de code template pour arriver à cette valeur, nous nous trouvons clairement dans une situation dans laquelle cela ne changera rien Citation:
Je ne suis personnellement pas persuadé que le fait de pouvoir identifier une valeur numérique changera quoi que ce soit à ce que le client pourra faire avec le code qu'il a en sa possession Maintenant, je te rappelle que je parle de manière tout à fait générale, sans connaitre les tenants et les aboutissants de ton projet Citation:
Citation:
J'ai participé il y a quelques semaines à une discussion qui portait à peu près sur ce thême, et qui te donnera peut etre quelques pistes à suivre En résumé : il y a peut etre un bug avec g++, ou non, mais le meilleur moyen de t'assurer que tout fonctionne bien est d'être sur que le fichier objet dans lequel ta constante statique est initialisée apparaisse avant tous les fichiers objets dans lequel elle est utilisée lors de l'édition de liens. (bon, c'est peut etre pas très clair, alors, si tu ne comprends pas, fait moi signe Citation:
__________________
en bas de page
|
|||||
|
|
00
|
|
|
#11 | |
|
Nouveau Membre du Club
![]() Camille GillotÉtudiant Inscription : septembre 2007 Messages : 47 ![]() |
Citation:
, enfin... si jamais on en arrivait là, tout irait bien .Le symptôme se montre plus tôt, au linkage : dans le cas -O0, truc.o contient un symbole A<int>:: x, mais si on optimise -O2, truc.o ne le contient plus et le link échoue. Je voudrais juste savoir si il y a un moyen de forcer le symbole A<int>:: x à apparaître dans a.o. |
|
|
|
00
|
|
|
#12 | |||||||
![]() ![]() |
En fait, je ne sais pas s'il s'agit "simplement" du comportement "normal" d'une des optimisations activées avec -O2 et qu'il suffirait de désactiver (pour tout fKKC, il y a un -f-no-KKC
![]() Ceci dit, la seule solution pour être sur que cette valeur sera correctement initialisée est et restera l'encapsulation... Tu pourrais par exemple, remplacer ta variable membre statique x par une fonction statique, sous la forme de Code :
(note que tu peux même envisager de la déclarer constexpr en C++11 Ceci dit, comme je me plais à le rappeler, on peut aussi penser à une phrase sympa de Citation:
a.hpp Code :
Code :
__________________
en bas de page
|
|||||||
|
|
00
|
|
|
#13 | ||
|
Nouveau Membre du Club
![]() Camille GillotÉtudiant Inscription : septembre 2007 Messages : 47 ![]() |
Que ce soit une fonction ou variable statique, le problème est le même si l'instantiation n'advient pas.
L'initialisation statique est un fait acquis déjà, pas la peine de t'en préoccuper. J'ai fini par trouver une réponse tout seul : le mot-clé volatile s'appelle dieu quand l'optimiseur est trop zélé. Code final : Code :
Merci quand-même pour les conseils généraux. |
||
|
|
00
|
Copyright © 2000-2013 - www.developpez.com