2009-12-02 10 views
1

Je dois convertir un type intégral qui contient une adresse en type de pointeur réel. Je pourrais utiliser reinterpret_cast comme suit:C++: moyen sûr de convertir un entier en pointeur

MyClass *mc1 = reinterpret_cast<MyClass*>(the_integer); 

Cependant, cela n'effectue aucun contrôle d'exécution pour voir si l'adresse en question tient en fait un objet MyClass. Je veux savoir s'il y a un avantage à convertir d'abord en un void * (en utilisant reinterpret_cast) puis en utilisant dynamic_cast sur le résultat. Comme ceci:

void *p = reinterpret_cast<void*>(the_integer); 
MyClass *mc1 = dynamic_cast<MyClass*>(p); 
assert(mc1 != NULL); 

Y at-il un avantage à utiliser la seconde méthode?

+4

La deuxième méthode n'est pas légale C++, le type de l'expression à dynamic_cast peut ne pas être vide *. –

+2

En supposant que la valeur entière était à l'origine un pointeur sur un objet. Un int ne peut potentiellement pas contenir le pointeur. C'est pourquoi nous avons void *. Si vous lancez des pointeurs pour le transport à travers une frontière non typée, vous devez les convertir en void * et revenir au type d'origine. –

+0

Il n'a pas dit 'int' spécifiquement, le type pourrait être intptr_t. –

Répondre

2

La vérification de type sur dynamic_cast est implémentée de différentes manières par différentes implémentations C++; Si vous voulez une réponse pour votre implémentation spécifique, vous devez mentionner quelle implémentation vous utilisez. La seule façon de répondre à la question en général est de se référer à la norme ISO C++.

par ma lecture de la norme, appelant dynamic_cast sur un pointeur vide est illégal:

dynamic_cast<T>(v) 

« Si T est un type de pointeur, V est un rvalue d'un pointeur pour compléter le type de classe »

(à partir de 5.2.7.2 de la norme ISO C++). void n'est pas un type de classe complet, donc l'expression est illégale.

Fait intéressant, le type étant jeté - est autorisé à être un pointeur vide, ce

void * foo = dynamic_cast<void *>(some_pointer); 

Dans ce cas, l'dynamic_cast réussit toujours, et la valeur résultante est un pointeur vers le plus dérivé objet pointé par v.

+1

Ceci est dû au fait qu'après 'void * foo = dynamic_cast (un_pointer);', vous pouvez trouver 'foo! = Some_pointer' (ce qui signifie que \ _pointer pointait sur un sous-objet de base). –

2

Non, il n'y a pas d'avantage particulier à le faire. Au moment où vous utilisez reinterpret_cast, tous les paris sont désactivés. C'est à vous de vous assurer que la distribution est valide.

2

En fait pas d'avantage sérieux. Si le void * pointe vers quelque chose qui n'est pas un pointeur vers un objet polymorphe, vous rencontrez un comportement non défini (généralement une violation d'accès) immédiatement.

+2

Sauf quand vous ne le faites pas. S'appuyer sur un comportement indéfini n'est jamais une idée intelligente. –

1

Le moyen le plus sûr est de conserver un enregistrement de tous les objets Live MyClass. Il est préférable de conserver cet enregistrement dans un std::set<void*>, ce qui signifie que vous pouvez facilement ajouter, supprimer et tester des éléments.

Si vous les stockez sous la forme void*, vous ne risquez pas de créer des pointeurs MyClass* non alignés à partir de vos entiers.

0
  • d'abord "réinterprète" int à void * est une mauvaise idée. Si sizeof(int) est 4 et sizeof(void *) est 8 (système 64x), il est mal formé. Par ailleurs, dynamic_cast est valable uniquement dans le cas des classes polymorphes.

0

Si vous êtes sûr que the_integer des points à une classe de base connue (qui a au moins un membre virtuel), il pourrait en fait être un avantage: sachant que l'objet est d'une classe dérivée spécifique. Mais vous auriez à reinterpret_cast à votre classe de base d'abord, puis faites le dynamic_cast:

BaseClass* obj = reinterpret_cast<BaseClass*>(the_integer); 
MyClass* myObj = dynamic_cast<BaseClass*>(obj); 

L'utilisation d'un void* dans dynamic_cast est inutile et tout simplement faux. Vous ne pouvez pas utiliser dynamic_cast pour vérifier s'il existe un objet valide dans un emplacement arbitraire en mémoire.

Vous devez également faire attention lorsque vous stockez des adresses dans des variables de type non-pointeur. Il existe des architectures où sizeof (void *)! = Sizeof (int), par ex. LP64.

0

L'option 1 est votre seule option (semi) portable/valide.

Option 2: C++ n'est pas valide en tant que dynamic_cast (car void n'est pas autorisé). Au niveau de l'implémentation, il faut des informations de type du type source pour accéder au type de destination. Il n'y a aucun moyen (ou il n'y a aucun moyen) d'obtenir les informations de type source d'exécution à partir d'un void *, ce qui n'est pas non plus valable. DynamicCast est utilisé pour monter et descendre la hiérarchie de types et non pas de types inconnus.

En remarque, vous devriez probablement utiliser void * plutôt qu'un nombre entier pour stocker un pointeur non typé. Il est possible qu'un int ne soit pas assez grand pour stocker un pointeur.

0

La façon la plus sûre de gérer les pointeurs en C++ est de les gérer de type typesafe. Cela signifie:

  • Ne jamais stocker des pointeurs dans quoi que ce soit d'autre qu'un pointeur
  • Évitez les pointeurs vides
  • Ne jamais passer des pointeurs vers d'autres processus
  • considèrent weak_ptr si vous prévoyez d'utiliser des pointeurs sur des fils

La raison en est: ce que vous avez l'intention de faire est dangereux et peut être évité à moins que vous ne vous interfaçiez avec un code dangereux (héritage?). Dans ce cas, considérez la réponse de MSalters, mais sachez que c'est toujours un problème.

Questions connexes