Question Pourquoi utiliser static_cast (x) au lieu de (int) x?


J'ai entendu que le static_cast La fonction devrait être préférée au style C ou à la fonction simple. Est-ce vrai? Pourquoi?


529
2017-09-19 16:33


origine


Réponses:


La raison principale est que les castes C classiques ne font aucune distinction entre ce que nous appelons static_cast<>(), reinterpret_cast<>(), const_cast<>(), et dynamic_cast<>(). Ces quatre choses sont complètement différentes.

UNE static_cast<>() est habituellement sans danger. Il existe une conversion valide dans la langue ou un constructeur approprié qui la rend possible. La seule fois où c'est un peu risqué, c'est quand vous tombez dans une classe héritée; vous devez vous assurer que l'objet est réellement le descendant que vous prétendez être, par des moyens externes à la langue (comme un drapeau dans l'objet). UNE dynamic_cast<>() est sûr tant que le résultat est vérifié (pointeur) ou qu'une exception éventuelle est prise en compte (référence).

UNE reinterpret_cast<>() (ou un const_cast<>()) d'autre part est toujours dangereux. Vous dites au compilateur: "faites-moi confiance: je sais que cela ne ressemble pas à foo (Cela semble ne pas être mutable), mais c'est ".

Le premier problème est qu'il est presque impossible de dire lequel se produira dans un casting de style C sans regarder de grandes pièces dispersées et de connaître toutes les règles.

Supposons ceci:

class CMyClass : public CMyBase {...};
class CMyOtherStuff {...} ;

CMyBase  *pSomething; // filled somewhere

Maintenant, ces deux sont compilés de la même manière:

CMyClass *pMyObject;
pMyObject = static_cast<CMyClass*>(pSomething); // Safe; as long as we checked

pMyObject = (CMyClass*)(pSomething); // Same as static_cast<>
                                     // Safe; as long as we checked
                                     // but harder to read

Cependant, voyons ce code presque identique:

CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert

pOther = (CMyOtherStuff*)(pSomething);            // No compiler error.
                                                  // Same as reinterpret_cast<>
                                                  // and it's wrong!!!

Comme vous pouvez le voir, il n'y a pas de moyen facile de faire la distinction entre les deux situations sans en savoir beaucoup sur toutes les classes impliquées.

Le deuxième problème est que les moulages de style C sont trop difficiles à localiser. Dans les expressions complexes, il peut être très difficile de voir des jets de style C. Il est pratiquement impossible d'écrire un outil automatisé qui a besoin de localiser des lancers de style C (par exemple un outil de recherche) sans un frontal du compilateur C ++. D'un autre côté, il est facile de rechercher "static_cast <" ou "reinterpret_cast <".

pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
      // No compiler error.
      // but the presence of a reinterpret_cast<> is 
      // like a Siren with Red Flashing Lights in your code.
      // The mere typing of it should cause you to feel VERY uncomfortable.

Cela signifie que non seulement les jets de style C sont plus dangereux, mais qu'il est beaucoup plus difficile de les trouver tous pour s'assurer qu'ils sont corrects.


528
2017-09-19 17:23



Une astuce pragmatique: vous pouvez rechercher facilement le mot-clé static_cast dans votre code source si vous envisagez de ranger le projet.


102
2017-09-19 16:59



En bref:

  1. static_cast<>() vous donne une capacité de vérification de temps de compilation, C-Style   le cast ne le fait pas.
  2. static_cast<>() peut être repéré facilement   n'importe où dans un code source C ++; en revanche, la distribution C_Style est plus difficile à repérer.
  3. Les intentions sont beaucoup mieux transmises en utilisant les distributions C ++.

Plus d'explication:

Le casting statique effectue des conversions entre types compatibles. Il   est similaire à la distribution en style C, mais est plus restrictive. Par exemple,   le cast de style C permettrait à un pointeur entier de pointer vers un char.

char c = 10;       // 1 byte
int *p = (int*)&c; // 4 bytes

Comme cela se traduit par un pointeur de 4 octets pointant sur 1 octet d'alloué   mémoire, l'écriture sur ce pointeur provoquera une erreur d'exécution ou   remplacera la mémoire adjacente.

*p = 5; // run-time error: stack corruption

Contrairement à la fonte de style C, la fonte statique permettra au   compilateur pour vérifier que les types de données pointeur et pointee sont   compatible, ce qui permet au programmeur d'attraper ce incorrect   affectation de pointeur pendant la compilation.

int *q = static_cast<int*>(&c); // compile-time error

En savoir plus sur:
Quelle est la différence entre static_cast <> et la coulée de style C
et
Cast régulier vs static_cast vs dynamic_cast  


55
2017-10-09 02:12



La question est plus importante que la simple utilisation de static_cast ou de cast de style C, car il y a différentes choses qui se produisent lors de l'utilisation de moulages de style C. Les opérateurs de cast C ++ sont destinés à rendre ces opérations plus explicites.

Sur la surface static_cast et les transtypages de style C apparaissent à la même chose, par exemple lors de la conversion d'une valeur en une autre:

int i;
double d = (double)i;                  //C-style cast
double d2 = static_cast<double>( i );  //C++ cast

Les deux lancent la valeur entière en double. Cependant, lorsque vous travaillez avec des pointeurs, les choses deviennent plus compliquées. quelques exemples:

class A {};
class B : public A {};

A* a = new B;
B* b = (B*)a;                                  //(1) what is this supposed to do?

char* c = (char*)new int( 5 );                 //(2) that weird?
char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error

Dans cet exemple (1) peut-être OK parce que l'objet pointé par A est vraiment une instance de B. Mais que se passe-t-il si vous ne savez pas à ce moment-là dans le code à quoi pointe réellement? (2) peut-être parfaitement légal (vous voulez seulement regarder un octet de l'entier), mais cela pourrait aussi être une erreur, auquel cas une erreur serait agréable, comme (3). Les opérateurs de casting C ++ sont destinés à exposer ces problèmes dans le code en fournissant des erreurs de compilation ou d'exécution lorsque cela est possible.

Ainsi, pour un "casting de valeur" strict, vous pouvez utiliser static_cast. Si vous voulez lancer des pointeurs polymorphes à l'exécution, utilisez dynamic_cast. Si vous voulez vraiment oublier les types, vous pouvez utiliser reintrepret_cast. Et pour lancer const dans la fenêtre, il y a const_cast.

Ils ne font que rendre le code plus explicite pour que vous sachiez ce que vous faites.


26
2017-09-19 16:46



static_cast signifie que vous ne pouvez pas accidentellement const_cast ou reinterpret_cast, Ce qui est une bonne chose.


21
2017-09-19 17:39



  1. Permet aux moules d'être trouvés facilement votre code en utilisant grep ou similaire outils.
  2. Rend explicite ce genre     de casting que vous faites, et engageant     l'aide du compilateur pour l'appliquer.     Si vous voulez seulement jeter     const-ness, alors vous pouvez utiliser     const_cast, qui ne vous permettra pas     faire d'autres types de conversions.
  3. Les castes sont intrinsèquement laids - vous en tant que         un programmeur sont en train de modifier la façon dont le         compilateur traiterait normalement votre         code. Vous dites à la         compilateur, "je sais mieux que vous."         Cela étant le cas, cela a du sens         que la réalisation d'un casting devrait être un         chose modérément douloureuse à faire, et         qu'ils devraient rester dans votre         code, car ils sont une source probable         des problèmes.

Voir C ++ efficace introduction


7
2017-09-19 16:47



C'est à propos de la sécurité que vous voulez imposer.

Quand vous écrivez (bar) foo (ce qui équivaut à reinterpret_cast<bar> foo si vous n'avez pas fourni d'opérateur de conversion de type), vous dites au compilateur d'ignorer la sécurité de type, et faites comme il est dit.

Quand vous écrivez static_cast<bar> foo vous demandez au compilateur de vérifier au moins que la conversion de type a du sens et, pour les types entiers, d'insérer un code de conversion.


EDIT 2014-02-26

J'ai écrit cette réponse il y a plus de 5 ans, et je me suis trompé. (Voir les commentaires.) Mais il y a toujours des upvotes!


7
2017-09-19 17:29



Les moulages de style C sont faciles à manquer dans un bloc de code. Les jets de style C ++ ne sont pas seulement de meilleures pratiques; ils offrent beaucoup plus de flexibilité.

reinterpret_cast permet l'intégration aux conversions de type pointeur, mais peut être dangereuse si elle est mal utilisée.

static_cast offre une bonne conversion pour les types numériques, par ex. de comme enums à ints ou ints à floats ou tout type de données que vous êtes confiant de type. Il n'effectue aucun contrôle de durée d'exécution.

D'autre part, dynamic_cast effectuera ces contrôles signalant toute affectation ou conversion ambiguë. Cela ne fonctionne que sur les pointeurs et les références et entraîne une surcharge.

Il y en a quelques autres mais ce sont les principaux que vous rencontrerez.


4
2017-09-19 16:37