2010-02-27 5 views
12

J'ai beaucoup lu sur le casting en C++ et je commence à être confus parce que j'ai toujours utilisé le casting de style C. J'ai lu que le casting de style C devrait être évité en C++ et que reinterpret_cast est très très dangereux et ne devrait pas être utilisé quand il y a une alternative. Au contraire de ne pas utiliser reinterpret_cast, je l'ai vu utilisé plusieurs fois sur MSDN dans leur exemple de code. Cela m'amène à poser ma première question, quand est-ce que je peux utiliser reinterpret_cast?Confusion sur le casting C++

Par exemple:

LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) 
{ 
    switch (Msg) 
    { 
     case WM_CREATE: 
     { 
      LPCREATESTRUCT lpCreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam); 
      return 0; 
     } 
    } 

    ... 
} 

Si ce n'est pas correct, alors comment pourrais-je jeter la valeur lParam à un pointeur en utilisant uniquement statique, dynamique et/ou coulée const?

aussi: Si reinterpret_cast est pas portable, comment pourrais-je réécris pour être portable (pour les bonnes pratiques)

+1

Cela peut être une ancienne base de code. –

Répondre

8

L'utilisation reinterpret_cast est acceptable si vous savez que le pointeur était à l'origine du type de destination. Toute autre utilisation tire parti du comportement dépendant de l'implémentation, bien que dans de nombreux cas, cela soit nécessaire et utile, par exemple en passant un pointeur sur une structure dans un pointeur vers des octets pour pouvoir être sérialisé.

Il est considéré comme dangereux car il ne fait aucun contrôle, que ce soit au moment de la compilation ou au moment de l'exécution. Si vous faites une erreur, il peut et va planter et brûler horriblement, et être difficile à déboguer. Vous dites essentiellement au compilateur "Je sais mieux que vous ce que c'est réellement, alors compilez simplement le code et laissez-moi m'inquiéter des conséquences."

+1

Sérialiser les structures de cette façon est une mauvaise idée (même si c'est très souvent fait), mais c'est un sujet pour une autre question. – Tronic

5

La raison pour laquelle vous voyez sur MSDN est parce que l'API Win32 est une API C , mais les gens insistent pour donner des exemples dans C++. Ré-interpréter la distribution est très bien lorsque vous écrivez du code qui s'interface avec d'autres bibliothèques. Il devrait être évité au sein de votre propre application.

2

Pour ne pas manquer de respect à MSDN, mais MSDN n'est pas le meilleur endroit où aller pour un codage C++ approprié.

Une raison d'utiliser reinterpret_cast est lorsque vous transtypez vers/depuis des types de données opaques. reinterpret_cast n'est pas "dangereux" c'est juste qu'il est facile de bousiller et d'engendrer des problèmes dans votre code, c'est pourquoi il faut l'éviter.

La raison pour laquelle les castings de style C++ sont préférés est que static_cast est de type safe, et que tous les temps d'incantation sont plus faciles à rechercher.

Les programmeurs [incorrectement] utilisent souvent des conversions pour «éliminer les avertissements du compilateur», comme la conversion d'entiers non signés en entiers signés, ou d'un entier 32 bits à un entier 8 bits.

+1

+1. MSDN est plein de MS-isms. Les bons livres de Scott Meyers et Herb Sutter (bien qu'il soit maintenant à MS, il est un excellent écrivain et a beaucoup de bons conseils sur la façon d'écrire du bon C++) sont de meilleurs endroits pour cimenter la bonne pratique du C++. –

+0

@Matt Curtis - Je trouve que la partie la plus ennuyante à propos de MSDN est que les MS-isms sont appliquées de manière incohérente. La qualité varie beaucoup avec leurs exemples. D'une manière générale, cependant, vous ne devriez pas copier-coller leurs exemples; Cela peut vous donner une idée approximative, mais vous devez adapter ces idées à tout style de codage utilisé dans le projet sur lequel vous travaillez. – asveikau

2

essentiellement reinterpret_cast est « sûr » avec des structures C et les types de base (mettant à nu des erreurs simples comme coulée int à un pointeur et le dos, qui travaille sur l'architecture ILP32 mais les pauses sur un LP64.) La structure AC n'a rien en elle , sauf un remplissage possible pour l'alignement, que vous n'avez pas déclaré.

reinterpret_cast est pas en sécurité avec des types polymorphes C depuis de compilateur insère des éléments de données dans votre classe - des choses comme pointeurs vers des tables virtuelles et pointeurs vers des classes de base virtuelles. D'autres distributions C++ prennent soin de les ajuster lorsque, disons, la conversion de pointeur en classe de base en pointeur en classe dérivée, reinterpret_cast et les conversions en style C ne le font pas.

3

Ceci est un exemple de programmation de Windows Platform SDK, une API C, avec C++. La procédure de fenêtre a seulement les paramètres WPARAM et LPARAM et si vous devez passer un pointeur à une structure à travers un message de fenêtre, il doit être cast. C'est une utilisation tout à fait acceptable de reinterpret_cast <> à mon avis. Vous ne pouvez pas éviter une distribution, car le SDK que vous écrivez, qui n'est pas votre code, n'a pas été conçu pour C++, et encore moins pour la sécurité de type, et a besoin de la conversion pour fournir des types de paramètres génériques avec une liaison C. Le reinterpret_cast <> Voici un drapeau qui vous indique que vous devez faire attention, mais il ne doit pas être évité à tout prix. Si, d'un autre côté, vous contrôliez les deux côtés du code, l'API et le consommateur, il serait préférable de créer une API qui soit sûre pour le type et qui n'oblige pas le consommateur à effectuer des conversions pour l'utiliser correctement.