Dlaczego warto używać static cast (x) zamiast (int)x?

Słyszałem, że funkcja static_cast powinna być preferowana do c-style lub prostego odlewania w stylu funkcji. Czy to prawda? Dlaczego?

Author: Sisir, 2008-09-19

9 answers

Głównym powodem jest to, że Klasyczne odlewy C nie rozróżniają tego, co nazywamy static_cast<>(), reinterpret_cast<>(), const_cast<>(), i dynamic_cast<>(). Te cztery rzeczy są zupełnie inne.

A static_cast<>() jest zwykle bezpieczny. Istnieje poprawna konwersja w języku lub odpowiedni konstruktor, który to umożliwia. Jedynym czasem, kiedy jest to trochę ryzykowne, jest to, że odrzucasz do odziedziczonej klasy; musisz upewnić się, że obiekt jest rzeczywiście potomkiem, który twierdzisz, że jest, za pomocą zewnętrznych środków języka (jak flaga w obiekcie). A dynamic_cast<>() jest bezpieczne, o ile wynik jest sprawdzany (wskaźnik) lub uwzględniany jest ewentualny wyjątek (odniesienie).

A reinterpret_cast<>() (lub const_cast<>()) z drugiej strony jest zawsze niebezpieczne. Możesz powiedzieć kompilatorowi: "zaufaj mi: Wiem, że to nie wygląda jak foo (wygląda tak, jakby nie było mutowalne), ale tak jest".

Pierwszy problem polega na tym, że prawie niemożliwe jest określenie, który z nich wystąpi w obsadzie w stylu C bez patrzenia na duże i rozproszone kawałki kod i znajomość wszystkich zasad.

Załóżmy, że:

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

CMyBase  *pSomething; // filled somewhere

Teraz te dwa są zestawiane w ten sam sposób:

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

Jednak spójrzmy na ten prawie identyczny kod:

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

Jak widzisz, nie ma łatwego sposobu, aby odróżnić te dwie sytuacje, nie wiedząc wiele o wszystkich klasach zaangażowanych.

Drugi problem polega na tym, że odlewy w stylu C są zbyt trudne do zlokalizowania. W złożonych wyrażeniach może być bardzo trudno zobaczyć odlewy w stylu C. Jest to praktycznie niemożliwe, aby napisać zautomatyzowane narzędzie, które musi zlokalizować odlewy w stylu C (na przykład narzędzie wyszukiwania) bez pełnego kompilatora C++ front-end. Z drugiej strony łatwo jest wyszukać "static_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.

Oznacza to, że nie tylko rzuty w stylu C są bardziej niebezpieczne, ale o wiele trudniej jest znaleźć je wszystkie, aby upewnić się, że są poprawne.

 654
Author: Euro Micelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-13 10:38:27

Jedna pragmatyczna WSKAZÓWKA: Możesz łatwo wyszukać słowo kluczowe static_cast w kodzie źródłowym, jeśli planujesz uporządkować projekt.

 117
Author: Karl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 16:59:17

W skrócie :

  1. static_cast<>() daje możliwość sprawdzania czasu kompilacji, w stylu C Obsada Nie.
  2. static_cast<>() można łatwo zauważyć w dowolnym miejscu wewnątrz kodu źródłowego C++; w przeciwieństwie do c_style cast jest trudniejszy do zauważenia.
  3. intencje są znacznie lepiej przekazywane za pomocą C++.

Więcej Wyjaśnień :

Static cast wykonuje konwersje pomiędzy kompatybilnymi typami . Informatyka jest podobny do obsady w stylu C, ale jest bardziej restrykcyjna. Na przykład, rzut w stylu C pozwala na wskazanie wskaźnika integer na znak.

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

Ponieważ daje to 4-bajtowy wskaźnik wskazujący na 1 bajt przydzielonego pamięci, zapis do tego wskaźnika spowoduje błąd w czasie wykonywania lub nadpisze jakąś sąsiednią pamięć.

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

W przeciwieństwie do c-style Obsada statyczna pozwoli na kompilator sprawdzający, czy typy danych pointer i pointee są kompatybilny, co pozwala na programista, aby złapać ten niepoprawny przypisanie wskaźnika podczas kompilacji.

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

Czytaj więcej na:
Jaka jest różnica między static_cast a c style casting
oraz
Regular cast vs. static_cast vs. dynamic_cast

 83
Author: Rika,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:36

Pytanie jest większe niż tylko używanie wither static_cast lub c style casting, ponieważ istnieją różne rzeczy, które dzieją się podczas używania c style Casting. Operatory odlewania C++ mają na celu uczynienie tych operacji bardziej wyraźnymi.

Na powierzchni static_cast i odlewy w stylu C wyglądają tak samo, na przykład podczas odlewania jednej wartości na drugą:

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

Oba z nich rzucają wartość całkowitą na podwójną. Jednak podczas pracy ze wskaźnikami sprawy stają się bardziej skomplikowane. niektóre przykłady:

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

W tym przykładzie (1) może OK, ponieważ obiekt wskazywany przez A jest rzeczywiście instancją B. Ale co, jeśli nie wiesz w tym momencie w kodzie, do czego faktycznie wskazuje a? (2) może całkowicie legalne(chcesz spojrzeć tylko na jeden bajt liczby całkowitej), ale może to być również błąd, w którym to przypadku błąd byłby miły, jak (3). Operatory odlewania C++ mają na celu ujawnienie tych problemów w kodzie poprzez dostarczenie błędów w czasie kompilacji lub w czasie wykonywania, gdy możliwe.

Więc, dla ścisłego "odlewania wartości" można użyć static_cast. Jeśli chcesz polimorficznego odlewania wskaźników w czasie wykonywania, użyj dynamic_cast. Jeśli naprawdę chcesz zapomnieć o typach, możesz użyć reintrepret_cast. I po prostu wyrzucić const przez okno jest const_cast.

Po prostu sprawiają, że kod jest bardziej wyraźny, tak, że wygląda, jakbyś wiedział, co robisz.

 28
Author: Dusty Campbell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 17:24:30

static_cast oznacza, że nie możesz przypadkowo const_cast lub reinterpret_cast, co jest dobrą rzeczą.

 26
Author: DrPizza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-30 14:32:18
  1. umożliwia łatwe odnalezienie odlewów w Twój kod za pomocą grep lub podobnego narzędzia.
  2. wyjaśnia, jaki rodzaj z obsady, którą wykonujesz i angażujesz pomoc kompilatora w jej egzekwowaniu. If you only want to cast away const-ness, wtedy możesz użyć const_cast, który nie pozwoli Ci do wykonywania innych typów konwersji.
  3. rzuty są z natury brzydkie - Ty jako programista przerywa jak kompilator normalnie traktowałby Twoje kod. Mówisz do kompilator, " wiem lepiej niż ty." To ma sens. że wykonanie obsady powinno być umiarkowanie bolesna rzecz do zrobienia i że powinny wystawać w Twoim Kod, ponieważ są one prawdopodobnie źródłem problemów.

Zobacz Efektywne C++ Wprowadzenie

 8
Author: JohnMcG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 17:39:23

Chodzi o to, ile bezpieczeństwa typu chcesz narzucić.

Kiedy piszesz (bar) foo (co jest równoważne reinterpret_cast<bar> foo, jeśli nie podałeś operatora konwersji typu), mówisz kompilatorowi, aby zignorował bezpieczeństwo typu i po prostu zrobił to, co powiedział.

Kiedy piszesz static_cast<bar> foo, prosisz kompilator, aby przynajmniej sprawdził, czy konwersja typu ma sens i, dla typów całkowych, wstawił jakiś kod konwersji.


Edycja 2014-02-26

Napisałem tę odpowiedź ponad 5 lat temu, i pomyliłem się. (Patrz komentarze.) Ale i tak robi się coraz ciekawiej!

 7
Author: Pitarou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-25 23:19:46

Rzuty w stylu C są łatwe do pominięcia w bloku kodu. Odlewy w stylu C++ są nie tylko lepszą praktyką; oferują znacznie większy stopień elastyczności.

Reinterpret_cast pozwala na konwersje typu integral do typu pointer, jednak może być niebezpieczne w przypadku niewłaściwego użycia.

Static_cast oferuje dobrą konwersję dla typów liczbowych, np. z AS enums do ints lub ints do floats lub dowolnych typów danych, których typ jest pewny. Nie wykonuje żadnych kontroli czasu pracy.

Dynamic_cast z drugiej strony wykona te kontrole oznaczając wszelkie niejednoznaczne przydziały lub konwersje. Działa tylko na wskaźnikach i referencjach i ponosi koszty ogólne.

Jest kilka innych, ale są to główne z nich, które napotkasz.

 6
Author: Konrad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 17:29:08

Static_cast, oprócz manipulowania wskaźnikami do klas, może być również używany do wykonywania konwersji jawnie zdefiniowanych w klasach, a także do wykonywania standardowych konwersji między podstawowymi typami:

double d = 3.14159265;
int    i = static_cast<int>(d);
 4
Author: prakash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 16:37:03