Waarom static_cast<int>(x) gebruiken in plaats van (int)x?

Ik heb gehoord dat de functie static_castde voorkeur verdient boven C-stijl of eenvoudig casten in functiestijl. Is dit waar? Waarom?


Antwoord 1, autoriteit 100%

De belangrijkste reden is dat klassieke C-casts geen onderscheid maken tussen wat we noemen static_cast<>(), reinterpret_cast<>(), const_cast<>()en dynamic_cast<>(). Deze vier dingen zijn totaal verschillend.

Een static_cast<>()is meestal veilig. Er is een geldige conversie in de taal, of een geschikte constructor die het mogelijk maakt. De enige keer dat het een beetje riskant is, is wanneer je neerkomt op een geërfde klasse; je moet ervoor zorgen dat het object daadwerkelijk de afstammeling is waarvan je beweert dat het is, door middel van buiten de taal (zoals een vlag in het object). Een dynamic_cast<>()is veilig zolang het resultaat wordt gecontroleerd (pointer) of er rekening wordt gehouden met een eventuele uitzondering (referentie).

Een reinterpret_cast<>()(of een const_cast<>()) aan de andere kant is altijd gevaarlijk. Je zegt tegen de compiler: “Vertrouw me: ik weet dat dit er niet uitziet als een foo(dit ziet eruit alsof het niet veranderlijk is), maar het is het wel”.

Het eerste probleem is dat het bijna onmogelijk is om te zeggen welke zal voorkomen in een cast in C-stijl zonder naar grote en verspreide stukjes code te kijken en alle regels te kennen.

Laten we deze aannemen:

class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;
CMyBase  *pSomething; // filled somewhere

Deze twee zijn nu op dezelfde manier gecompileerd:

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

Laten we echter deze bijna identieke code eens bekijken:

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!!!

Zoals je kunt zien, is er geen gemakkelijke manier om onderscheid te maken tussen de twee situaties zonder veel te weten over alle betrokken klassen.

Het tweede probleem is dat de casts in C-stijl te moeilijk te vinden zijn. In complexe uitdrukkingen kan het erg moeilijk zijn om casts in C-stijl te zien. Het is vrijwel onmogelijk om een ​​geautomatiseerde tool te schrijven die C-stijl casts moet lokaliseren (bijvoorbeeld een zoekfunctie) zonder een volledige C++ compiler front-end. Aan de andere kant is het gemakkelijk om te zoeken naar “static_cast<” of “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.

Dat betekent dat casts in C-stijl niet alleen gevaarlijker zijn, maar dat het ook een stuk moeilijker is om ze allemaal te vinden om er zeker van te zijn dat ze correct zijn.


Antwoord 2, autoriteit 18%

Eén pragmatische tip: u kunt gemakkelijk zoeken naar het trefwoord static_cast in uw broncode als u van plan bent het project op te ruimen.


Antwoord 3, autoriteit 15%

Kortom:

  1. static_cast<>()geeft je de mogelijkheid om de compileertijd te controleren, C-Style
    cast niet.
  2. static_cast<>()kan gemakkelijk worden gezien
    overal in een C++-broncode; daarentegen is de cast van C_Style moeilijker te herkennen.
  3. Intenties worden veel beter overgebracht met C++ casts.

Meer uitleg:

De statische cast voert conversies uit tussen compatibele typen. Het
is vergelijkbaar met de C-stijl cast, maar is meer beperkend. Bijvoorbeeld,
de cast in C-stijl zou toestaan ​​dat een integer-pointer naar een char verwijst.

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

Aangezien dit resulteert in een 4-byte pointer die wijst naar 1 byte toegewezen
geheugen, zal het schrijven naar deze aanwijzer ofwel een runtime-fout veroorzaken of
zal een aangrenzend geheugen overschrijven.

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

In tegenstelling tot de cast in C-stijl, zorgt de statische cast ervoor dat de
compiler om te controleren of de datatypes pointer en pointee zijn
compatibel, waardoor de programmeur dit onjuist kan detecteren
aanwijzertoewijzing tijdens compilatie.

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

Lees meer over:
Wat is het verschil tussen static_cast<> en C-stijl casting
en
Reguliere cast versus static_cast versus dynamic_cast


Antwoord 4, autoriteit 4%

De vraag is groter dan alleen het gebruik van Wither static_cast of C-stijl casten, omdat er verschillende dingen gebeuren bij het gebruik van C-stijl casts. De C++ casting-operators zijn bedoeld om deze bewerkingen explicieter te maken.

Op het eerste gezicht lijken casts in static_cast en C-stijl op hetzelfde, bijvoorbeeld bij het casten van de ene waarde naar de andere:

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

Beide werpen de integerwaarde op een double. Bij het werken met wijzers wordt het echter ingewikkelder. enkele voorbeelden:

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

In dit voorbeeld (1) misschien OK omdat het object waarnaar A verwijst in werkelijkheid een instantie van B is. Maar wat als je op dat punt in de code niet weet waar a eigenlijk naar verwijst? (2) misschien volkomen legaal (je wilt maar naar één byte van het gehele getal kijken), maar het kan ook een fout zijn, in welk geval een fout leuk zou zijn, zoals (3). De C++ casting-operators zijn bedoeld om deze problemen in de code aan het licht te brengen door waar mogelijk compile-time- of runtime-fouten te geven.

Dus voor strikte “value casting” kun je static_cast gebruiken. Als je runtime polymorfe casting van pointers wilt, gebruik dan dynamic_cast. Als je typen echt wilt vergeten, kun je reintrepret_cast gebruiken. En om const gewoon uit het raam te gooien is er const_cast.

Ze maken de code alleen maar explicieter zodat het lijkt alsof je weet wat je aan het doen was.


Antwoord 5, autoriteit 4%

static_castbetekent dat je niet per ongeluk const_castof reinterpret_castkunt gebruiken, wat een goede zaak is.


Antwoord 6

  1. Hiermee kunnen casts gemakkelijk worden gevonden in
    uw code met grep of iets dergelijks
    hulpmiddelen.
  2. Maakt duidelijk wat voor soort
    van de cast die je aan het doen bent, en boeiend
    de hulp van de compiler bij het afdwingen ervan.
    Als je alleen maar wilt weggooien
    const-ness, dan kunt u gebruiken
    const_cast, die je niet zal toestaan
    om andere soorten conversies uit te voeren.
  3. Afgietsels zijn van nature lelijk — jij als
    een programmeur overheerst hoe de
    compiler zou normaal gesproken uw behandelen
    code. Je zegt tegen de
    compiler, “Ik weet het beter dan jij.”
    Dat het geval is, het is logisch
    dat het uitvoeren van een cast zou moeten zijn
    matig pijnlijk ding om te doen, en
    dat ze in je moeten blijven
    code, omdat ze een waarschijnlijke bron zijn
    van problemen.

Zie Effectief C++ Introductie


Antwoord 7

Het gaat over het aantal type-veiligheid dat u wilt opleggen.

Wanneer u (bar) fooschrijft (die gelijk is aan reinterpret_cast<bar> fooAls u geen conversie van het type hebt verstrekt), vertelt u de compiler om het type veiligheid te negeren en gewoon te doen zoals het wordt verteld.

Wanneer u schrijft static_cast<bar> fooU vraagt ​​de compiler om op zijn minst te controleren of de conversie van het type logisch is en, voor integrale types, om een ​​conversiecode in te voegen.


Bewerken 2014-02-26

Ik heb dit antwoord meer dan 5 jaar geleden geschreven, en ik heb het verkeerd. (Zie opmerkingen.) Maar het wordt nog steeds upvotes!


Antwoord 8

C-style-casts zijn gemakkelijk te missen in een blok code. C++ Style-casts zijn niet alleen een betere praktijk; Ze bieden een veel grotere mate van flexibiliteit.

REINTERPRET_CACCAD maakt integraal mogelijk om conversies te worden, maar kan echter onveilig zijn als het wordt misbruikt.

Static_cast biedt goede conversie voor numerieke types, b.v. Van als ENUM’s tot inten of ints tot drijft of alle gegevenstypen bent u ervan overtuigd van het type. Het voert geen runtime-cheques uit.

Dynamic_cast aan de andere kant zal deze cheques uitvoeren die ambigue opdrachten of conversies markeren. Het werkt alleen aan aanwijzingen en referenties en maakt een overhead.

Er zijn een paar anderen, maar dit zijn de belangrijkste die je tegenkomt.


Antwoord 9

Static_cast, afgezien van het manipuleren van aanwijzingen naar klassen, kan ook worden gebruikt om conversies uit te voeren die expliciet worden gedefinieerd in klassen, en om standaard conversies uit te voeren tussen fundamentele typen:

double d = 3.14159265;
int    i = static_cast<int>(d);

Other episodes