60 votes

Utilisation bizarre de `?:` Dans le code `typeid`

Dans l'un des projets sur lequel je travaille, je vais voir ce code

struct Base {
  virtual ~Base() { }
};

struct ClassX {
  bool isHoldingDerivedObj() const {
    return typeid(1 ? *m_basePtr : *m_basePtr) == typeid(Derived);
  }
  Base *m_basePtr;
};

Je n'ai jamais vu typeid utilisé comme ça. Pourquoi faut-il faire bizarre de danse avec ?:, au lieu de simplement faire typeid(*m_basePtr)? Pourrait-il y avoir une raison? Base est un polymorphe de la classe (avec un destructeur virtuel).

EDIT: À un autre endroit du présent code, je le vois et il semble être un équivalent de "superflu"

template<typename T> T &nonnull(T &t) { return t; }

struct ClassY {
  bool isHoldingDerivedObj() const {
    return typeid(nonnull(*m_basePtr)) == typeid(Derived);
  }
  Base *m_basePtr;
};

48voto

curiousguy Points 2900

Je pense que c'est de l'optimisation! Peu connu, sont rarement (on pourrait dire "jamais"), caractéristique de l' typeid est un déréférencement de pointeur nul de l'argument de l' typeid déclenche une exception au lieu de l'habituel UB.

Quoi? Êtes-vous sérieux? Êtes-vous en état d'ébriété?

En effet. Oui. Pas de.

int *p = 0;
*p; // UB
typeid (*p); // lance

Oui, c'est moche, même par la norme C++ de la langue de la laideur.

Otoh, que, cela ne veut pas travailler n'importe où à l'intérieur de l'argument de l' typeid, l'ajout d'une image de fond d'annuler cette "fonctionnalité":

int *p = 0;
typeid(1 ? *p *p); // UB
typeid(pièce d'identité(*p)); // UB

Pour mémoire: je ne prétends pas dans le message de vérification automatique par le compilateur qu'un pointeur n'est pas null avant de faire un déréférencement est forcément un truc de fou. Je dis seulement que le fait de vérifier, lorsque le déréférencement est le premier argument de l' typeid, et pas ailleurs, est totalement fou. (Peut-être que c'était une blague, inséré dans certains projets, et de ne jamais supprimé.)

Pour mémoire: je ne prétends pas dans le précédent "Pour le dossier" qu'il fait sens pour le compilateur insérer des contrôles automatiques qu'un pointeur n'est pas null, et de lever une exception (comme en Java) lorsqu'une valeur null est déréférencé: en général, la levée d'une exception sur un déréférencement de pointeur nul est absurde. C'est une erreur de programmation, donc une exception ne va pas aider. Un échec d'assertion est appelé pour.

5voto

Ben Jackson Points 28358

Le seul effet que je peux voir, c'est qu' 1 ? X : X vous donne X comme une rvalue au lieu de la plaine X ce qui pourrait être une lvalue. Ce peut importe d' typeid() pour des choses comme des tableaux (décomposition de pointeurs), mais je ne pense pas que cela aurait de l'importance s' Derived est connue pour être une classe. Peut-être qu'il a été copié à partir dans un endroit où les rvalue-ness n'a de l'importance? Qui prendrait en charge le commentaire à propos de "culte du cargo de programmation"

Concernant le commentaire ci-dessous j'ai fait un test et bien sûr, typeid(array) == typeid(1 ? array : array), donc dans un sens je me trompe, mais mon incompréhension peut encore correspondre à l'incompréhension qui conduisent à l'original du code!

0voto

Tony Points 36

Je soupçonne que certains compilateurs étaient, pour le cas simple de

 typeid(*m_basePtr)
 

retournant typeid (Base) toujours , quel que soit le type d'exécution. Mais passer à une expression / temporaire / rvalue oblige le compilateur à donner le RTTI.

La question est de savoir quel compilateur, quand, etc. Je pense que GCC a eu des problèmes avec typeid tôt, mais c'est un vague souvenir.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X