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?
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_castpOther = 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.
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.
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 :
static_cast<>()
daje możliwość sprawdzania czasu kompilacji, w stylu C Obsada Nie.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.- 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
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.
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ą.
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
- umożliwia łatwe odnalezienie odlewów w Twój kod za pomocą grep lub podobnego narzędzia.
- 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.
- 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
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!
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.
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);
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