OVH Cloud OVH Cloud

type_info

15 réponses
Avatar
Christophe de VIENNE
Bonjour,

J'ai une petite question sur type_info.

Version courte : Est-il sûr de conserver un pointeur sur un type_info ?

Version un chouilla plus longue :
Je souhaite faire une map dont la clé est un type.
J'ai le choix entre :
std::map< type_info const *, mon_type_foncteur > m_table;
et
std::map< std::string, mon_type_foncteur > m_table;

Dans le second cas, j'indexerais type_info.name.
Je préfère la première alternative, mais est-elle valable ?


Merci

Christophe

--
Christophe de Vienne

10 réponses

1 2
Avatar
Falk Tannhäuser
Christophe de VIENNE wrote:

Bonjour,

J'ai une petite question sur type_info.

Version courte : Est-il sûr de conserver un pointeur sur un type_info ?
Oui, cf. § 5.2.8/1 de la Norme :

"The result of a typeid expression is an lvalue [...]. The lifetime
of the object referred to by the lvalue extends to the end of the
program. Whether or not the destructor is called for the type_info
object at the end of the program is unspecified."


Version un chouilla plus longue :
Je souhaite faire une map dont la clé est un type.
J'ai le choix entre :
std::map< type_info const *, mon_type_foncteur > m_table;
et
std::map< std::string, mon_type_foncteur > m_table;

Dans le second cas, j'indexerais type_info.name.
Je préfère la première alternative, mais est-elle valable ?


Je pense que ce qu'il faut faire est

struct CmpTypeInfo
{
bool operator()(std::type_info const* t1, std::type_info const* t2) const
{
return t1->before(*t2);
}
};

puis

std::map<type_info const*, mon_type_foncteur, CmpTypeInfo> m_table;

La Norme ne semble pas garantir que 'typeid' revoie le même objet
lorsqu'il est appelé plusieurs fois avec un argument du même type
(bien qu'une implémentation qui alloue un nouvel objet à chaque
fois ne me semble guère raisonnable), c'est pour cela qu'il vaut
mieux éviter de comparer les pointeurs.
De plus, la Norme (cf. § 18.5.1/7-8) donne très peu de garanties pour
char const* type_info::name() const;
il n'est même pas sûr que le nom soit unique pour chaque type -
{ return "Tralala"; }
me paraît être une implémentation conforme...

Falk

Avatar
Christophe de VIENNE
Christophe de VIENNE wrote:

Bonjour,

J'ai une petite question sur type_info.

Version courte : Est-il sûr de conserver un pointeur sur un type_info ?


Oui, cf. § 5.2.8/1 de la Norme :
"The result of a typeid expression is an lvalue [...]. The lifetime
of the object referred to by the lvalue extends to the end of the
program. Whether or not the destructor is called for the type_info
object at the end of the program is unspecified."



Merci pour la référence.

La Norme ne semble pas garantir que 'typeid' revoie le même objet
lorsqu'il est appelé plusieurs fois avec un argument du même type
(bien qu'une implémentation qui alloue un nouvel objet à chaque
fois ne me semble guère raisonnable), c'est pour cela qu'il vaut
mieux éviter de comparer les pointeurs.


Je présentais un truc dans ce goût là.

Merci beaucoup !

Christophe

--
Christophe de Vienne


Avatar
drkm
Falk Tannhäuser writes:

Je pense que ce qu'il faut faire est

struct CmpTypeInfo
{
bool operator()(std::type_info const* t1, std::type_info const* t2) const
{
return t1->before(*t2);
}
};

puis

std::map<type_info const*, mon_type_foncteur, CmpTypeInfo> m_table;

La Norme ne semble pas garantir que 'typeid' revoie le même objet
lorsqu'il est appelé plusieurs fois avec un argument du même type
(bien qu'une implémentation qui alloue un nouvel objet à chaque
fois ne me semble guère raisonnable), c'est pour cela qu'il vaut
mieux éviter de comparer les pointeurs.
De plus, la Norme (cf. § 18.5.1/7-8) donne très peu de garanties pour
char const* type_info::name() const;
il n'est même pas sûr que le nom soit unique pour chaque type -
{ return "Tralala"; }
me paraît être une implémentation conforme...


Voici deux citations intéresantes, dans ce contexte, de Modern C++
Design :

« A conforming (but not necessarily award-winning) implementation
can have type_info::name return the empty string for all
types. »

« The standard does not guarantee that each invocation of, say,
typeid(int) returns a reference to the same type_info object.
Consequently, you cannot compare pointers to type_info
objects. »

Toutes deux sont tirées de 2.8, « A Wrapper Around type_info ». Cette
section construit un type TypeInfo qui serait, je pense, un bon
candidat comme type de clef :

std::map< TypeInfo , mon_type_foncteur > m_table ;

--drkm, en recherche d'un stage : http://www.fgeorges.org/ipl/stage.html

Avatar
Falk Tannhäuser
drkm wrote:

Falk Tannhäuser writes:

Je pense que ce qu'il faut faire est

struct CmpTypeInfo
{
bool operator()(std::type_info const* t1, std::type_info const* t2) const
{
return t1->before(*t2);
}
};

puis

std::map<type_info const*, mon_type_foncteur, CmpTypeInfo> m_table;

La Norme ne semble pas garantir que 'typeid' revoie le même objet
Lire : "... renvoie le même objet"



lorsqu'il est appelé plusieurs fois avec un argument du même type
(bien qu'une implémentation qui alloue un nouvel objet à chaque
fois ne me semble guère raisonnable), c'est pour cela qu'il vaut
mieux éviter de comparer les pointeurs.
De plus, la Norme (cf. § 18.5.1/7-8) donne très peu de garanties pour
char const* type_info::name() const;
il n'est même pas sûr que le nom soit unique pour chaque type -
{ return "Tralala"; }
me paraît être une implémentation conforme...



Voici deux citations intéresantes, dans ce contexte, de Modern C++
Design :

« A conforming (but not necessarily award-winning) implementation
can have type_info::name return the empty string for all
types. »
D'accord.



« The standard does not guarantee that each invocation of, say,
typeid(int) returns a reference to the same type_info object.
Consequently, you cannot compare pointers to type_info
objects. »
D'accord aussi, bien que je disais qu'une telle implémentation ne me

paraît pas bien raisonnable - dans l'absence d'un ramasse-miettes,
le programme suivant (qui est certainement très utile dans la pratique...)

#include <typeinfo>
int main()
{
for(long i=0; i<2000000000L; ++i)
for(long j=0; j<2000000000L; ++j)
typeid(42);
return 0;
}

risquerait d'épuiser la mémoire disponible sur la plupart des
systèmes existants et à venir...


Toutes deux sont tirées de 2.8, « A Wrapper Around type_info ». Cette
section construit un type TypeInfo qui serait, je pense, un bon
candidat comme type de clef :

std::map< TypeInfo , mon_type_foncteur > m_table ;


L'utilisation de 'bool type_info::before(const type_info& rhs) const'
me semble suffire pour le but recherché - bien que la "collating
sequence" dont il est question dans § 18.5.1/1 ne soit pas spécifiée,
elle est censée établir un ordre total compatible avec les exigences
pour les containeurs associatifs mentionnées dans § 23.1.2/2 et décrits
dans § 25.3/4.

Falk


Avatar
drkm
Falk Tannhäuser writes:

drkm wrote:

« The standard does not guarantee that each invocation of, say,
typeid(int) returns a reference to the same type_info object.
Consequently, you cannot compare pointers to type_info
objects. »


D'accord aussi, bien que je disais qu'une telle implémentation ne me
paraît pas bien raisonnable - dans l'absence d'un ramasse-miettes,
le programme suivant (qui est certainement très utile dans la
pratique...)

#include <typeinfo>
int main()
{
for(long i=0; i<2000000000L; ++i)
for(long j=0; j<2000000000L; ++j)
typeid(42);
return 0;
}

risquerait d'épuiser la mémoire disponible sur la plupart des
systèmes existants et à venir...


Mouais. Je pense que l'intention à quelque chose à voir avec les
TUs. Je pressent quelque chose comme la volonté de permettre à des
fichiers objets compilés séparément d'utiliser leur propre instance de
type_info. Comme si cela pouvait faciliter la compilation séparée.
Ce qui ne poserait pas de problème.

Quelle est exactement l'intention du comité derrière ce point ?

Toutes deux sont tirées de 2.8, « A Wrapper Around type_info ».
Cette section construit un type TypeInfo qui serait, je pense, un
bon candidat comme type de clef :

std::map< TypeInfo , mon_type_foncteur > m_table ;


L'utilisation de 'bool type_info::before(const type_info& rhs)
const' me semble suffire pour le but recherché - bien que la
"collating sequence" dont il est question dans § 18.5.1/1 ne soit
pas spécifiée, elle est censée établir un ordre total compatible
avec les exigences pour les containeurs associatifs mentionnées dans
§ 23.1.2/2 et décrits dans § 25.3/4.


En quelque sorte, c'est bien le fait d'utiliser type_info::before()
que je propose. Puisque c'est ce qu'utilise TypeInfo. Ce type est
vraiment très simple. Il peut être construit à partir d'une référence
vers un std::type_info. Il fournit également deux membres name() et
before(). Et les opérateurs de comparaison.

En fait, je ne comprend pas pourquoi std::type_info comprend un
membre before(), remplissant les conditions de définition de l'ordre
total qui va bien, mais pas les opérateurs de comparaison. C'est
juste ce que fait TypeInfo, afin de pourvoir être utilisé directement
comme clef.

Je trouve cela plus simple pour cette utilisation : on définit une
fois pour toute cette petite classe, et on sait qu'on peut l'utiliser
comme telle. Plutôt que de risquer d'oublier de spécifier le
paramètre template de tri.

Mais il est vrai que les deux solutions ne sont pas très
différentes.

--drkm, en recherche d'un stage : http://www.fgeorges.org/ipl/stage.html


Avatar
kanze
Falk Tannhäuser wrote in message
news:<cfv9ak$85k$...

Je pense que ce qu'il faut faire est

struct CmpTypeInfo
{
bool operator()(std::type_info const* t1, std::type_info const* t2) const
{
return t1->before(*t2);
}
};

puis

std::map<type_info const*, mon_type_foncteur, CmpTypeInfo> m_table;


Tout à fait.

La Norme ne semble pas garantir que 'typeid' revoie le même objet
lorsqu'il est appelé plusieurs fois avec un argument du même type
(bien qu'une implémentation qui alloue un nouvel objet à chaque
fois ne me semble guère raisonnable), c'est pour cela qu'il vaut
mieux éviter de comparer les pointeurs.


Une implémentation qui envoie un nouvel objet chaque fois ne tient
effectivement pas la route. Rien n'empêche, en revanche, que
l'implémentation renvoie un objet static, et renvoie un objet different
dans différentes unités de compilation. Et il me semble même avoir
entendu dire que certaines implémentations renvoienr réelement des
objets différents quand les typeid ont été appelés dans des DLLs
différents.

De plus, la Norme (cf. § 18.5.1/7-8) donne très peu de garanties pour
char const* type_info::name() const;


C'est le moindre qu'on puisse dire.

il n'est même pas sûr que le nom soit unique pour chaque type -
{ return "Tralala"; }
me paraît être une implémentation conforme...


De même qu'une qui renvoie systèmatiquement "". Tout à fait conforme.

Dans la pratique, certaines implémentations renvoient bien quelque chose
d'utile et de lisible -- d'autres renvoient quelque chose d'idiotes
comme le nom manglé du types, qui n'a aucune utilité.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Falk Tannhäuser
drkm wrote:
Falk Tannhäuser writes:

drkm wrote:


Mouais. Je pense que l'intention à quelque chose à voir avec les
TUs. Je pressent quelque chose comme la volonté de permettre à des
fichiers objets compilés séparément d'utiliser leur propre instance de
type_info. Comme si cela pouvait faciliter la compilation séparée.
Ce qui ne poserait pas de problème.
Quelle est exactement l'intention du comité derrière ce point ?


Ah oui, je n'avais pas pensé à cela ! C'est vrai, ça pourrait
simplifier l'implémentation, sans produire de fuite de mémoire
comme je l'imaginais.
Il y aurait peut-être aussi le problème des bibliothèques dynamiques...

[...]
En quelque sorte, c'est bien le fait d'utiliser type_info::before()
que je propose. Puisque c'est ce qu'utilise TypeInfo. Ce type est
vraiment très simple. Il peut être construit à partir d'une référence
vers un std::type_info. Il fournit également deux membres name() et
before(). Et les opérateurs de comparaison.

En fait, je ne comprend pas pourquoi std::type_info comprend un
membre before(), remplissant les conditions de définition de l'ordre
total qui va bien, mais pas les opérateurs de comparaison. C'est
juste ce que fait TypeInfo, afin de pourvoir être utilisé directement
comme clef.


Je crois que seul un membre du comité pourrait répondre à cette question...

Falk


Avatar
Falk Tannhäuser
wrote:

Une implémentation qui envoie un nouvel objet chaque fois ne tient
effectivement pas la route. Rien n'empêche, en revanche, que
l'implémentation renvoie un objet static, et renvoie un objet different
dans différentes unités de compilation. Et il me semble même avoir
entendu dire que certaines implémentations renvoienr réelement des
objets différents quand les typeid ont été appelés dans des DLLs
différents.


Ack.



De plus, la Norme (cf. § 18.5.1/7-8) donne très peu de garanties pour
char const* type_info::name() const;


C'est le moindre qu'on puisse dire.

il n'est même pas sûr que le nom soit unique pour chaque type -
{ return "Tralala"; }
me paraît être une implémentation conforme...


De même qu'une qui renvoie systèmatiquement "". Tout à fait conforme.

Dans la pratique, certaines implémentations renvoient bien quelque chose
d'utile et de lisible -- d'autres renvoient quelque chose d'idiotes
comme le nom manglé du types, qui n'a aucune utilité.


Tu veux dire, sauf si on utilise quelque chose comme de tordu
comme

#include <cxxabi.h>

int status;
char* name = abi::__cxa_demangle(typeid(val).name(), 0, 0, &status))

avec la nécessité de faire 'free(name)' derrière ?

:-)

Falk


Avatar
drkm
Falk Tannhäuser writes:

#include <cxxabi.h>

int status;
char* name = abi::__cxa_demangle(typeid(val).name(), 0, 0, &status))

avec la nécessité de faire 'free(name)' derrière ?


Ce qui donne un argument supplémentaire pour l'utilisation d'un
wrapper autour de std::type_info, je trouve. Cela permet
éventuellement de fournir des implémentations différentes de
TypeInfo::name() selon la plateforme.

--drkm, en recherche d'un stage : http://www.fgeorges.org/ipl/stage.html

Avatar
kanze
Falk Tannhäuser wrote in message
news:<cg028s$f0e$...
wrote:

Une implémentation qui envoie un nouvel objet chaque fois ne tient
effectivement pas la route. Rien n'empêche, en revanche, que
l'implémentation renvoie un objet static, et renvoie un objet
different dans différentes unités de compilation. Et il me semble
même avoir entendu dire que certaines implémentations renvoienr
réelement des objets différents quand les typeid ont été appelés
dans des DLLs différents.


Ack.


Ça se comprend, si on comprend la conception de certaines
implémentations de DLL (conception qui correspond aux buts récherchés).

Ça se comprend si tu penses que pour le linker, std::type_info est une
classe comme une autres, et qu'elle n'a rien de spécial. Et puis, si tu
penses aux plug-ins, où le but, c'est que la DLL soit aussi autonôme que
possible -- qu'à la rigueur, la DLL a été compilée avec g++ et le
binaire avec VC++.

De plus, la Norme (cf. § 18.5.1/7-8) donne très peu de garanties
pour
char const* type_info::name() const;
C'est le moindre qu'on puisse dire.


il n'est même pas sûr que le nom soit unique pour chaque type -
{ return "Tralala"; }
me paraît être une implémentation conforme...


De même qu'une qui renvoie systèmatiquement "". Tout à fait conforme.

Dans la pratique, certaines implémentations renvoient bien quelque
chose d'utile et de lisible -- d'autres renvoient quelque chose
d'idiotes comme le nom manglé du types, qui n'a aucune utilité.


Tu veux dire, sauf si on utilise quelque chose comme de tordu
comme

#include <cxxabi.h>

int status;
char* name = abi::__cxa_demangle(typeid(val).name(), 0, 0, &status))

avec la nécessité de faire 'free(name)' derrière ?


Par exemple:-).

Il y a eu une proposition pour normaliser le contenu de name(). Il n'a
pas passé, pour de diverses raisons, mais si j'étais un implémenteur,
c'est certainement sur cette proposition que je me baserais. Seulement,
l'opposition à la proposition venait en fait des implémenteurs.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



1 2