it-swarm-tr.com

Neden (int) x yerine static_cast <int> (x) kullanmalı?

static_cast işlevinin C stili veya basit işlev stili dökümüne tercih edilmesi gerektiğini duydum. Bu doğru mu? Niye ya?

598
Tommy Herbert

Bunun ana nedeni klasik C kalıplarının static_cast<>(), reinterpret_cast<>(), const_cast<>() ve dynamic_cast<>() olarak adlandırdığımız şey arasında bir ayrım yapmamasıdır. Bu dört şey tamamen farklı.

Bir static_cast<>() genellikle güvenlidir. Dilde geçerli bir dönüşüm veya mümkün kılan uygun bir kurucu var. Biraz riskli olan tek zaman, kalıtsal bir sınıfa geçtiğinizde; Nesnenin aslında dışardan (nesne içindeki bir bayrak gibi) olduğunu iddia ettiğiniz soydan olduğundan emin olmalısınız. Bir dynamic_cast<>(), sonuç kontrol edildiğinde (işaretçi) ya da olası bir istisna hesaba katıldığı sürece (referans) güvenlidir.

Öte yandan, reinterpret_cast<>() (veya const_cast<>()) her zaman tehlikelidir. Derleyiciye şunları söyleyin: "güven bana: Bunun foo gibi görünmediğini biliyorum (bu değişmezmiş gibi görünüyor), ama öyledir".

İlk sorun, büyük ve dağınık kod parçalarına bakmadan ve tüm kuralları bilmeden C tarzında bir dökümde hangisinin olacağını söylemek neredeyse imkansızdır.

Bunları varsayalım:

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

CMyBase  *pSomething; // filled somewhere

Şimdi, bu ikisi aynı şekilde derlenmiştir:

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

Ancak, bu neredeyse aynı kodu görelim:

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

Görebildiğiniz gibi, ilgili tüm sınıflar hakkında çok fazla şey bilmeden iki durum arasında ayrım yapmanın kolay bir yolu yoktur.

İkinci sorun, C tarzı kalıpların bulunamamasıdır. Karmaşık ifadelerde, C tarzı yayınları görmek çok zor olabilir. Tamamen şişirilmiş bir C++ derleyici ön ucu olmadan C-tarzı yayınları (örneğin bir arama aracı) bulması gereken otomatik bir araç yazmak neredeyse imkansızdır. Öte yandan, "static_cast <" veya "reinterpret_cast <" aramak kolaydır.

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.

Bu, yalnızca C tarzı atmaların daha tehlikeli olması değil, aynı zamanda doğru olduklarından emin olmak için hepsini bulmak daha zor olduğu anlamına gelir.

586
Euro Micelli

Pragmatik bir ipucu: projeyi düzeltmeyi düşünüyorsanız, kaynak kodunuzdaki static_cast anahtar sözcüğünü kolayca arayabilirsiniz.

109
Karl

Kısacası :

  1. static_cast<>() size derleme zamanı kontrol etme yeteneği verir, C-Style almaz.
  2. static_cast<>(), C++ kaynak kodunun herhangi bir yerinde kolayca tespit edilebilir; aksine, C_Style cast'ı bulmak zordur.
  3. C++ atmalarını kullanarak niyetleri çok daha iyi iletilir.

Daha Fazla Açıklama :

Statik döküm, uyumlu türler arasında dönüşüm yapar. C tarzı oyuncuya benzer, ancak daha kısıtlayıcıdır. Örneğin, C tarzı döküm, bir tamsayı göstericisinin bir karakteri göstermesini sağlar.

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

Bu, 1 byte ayrılmış belleğe işaret eden 4 baytlık bir işaretçiyle sonuçlandığından, bu işaretçiye yazmak bir çalışma zamanı hatasına neden olur veya bitişik bazı belleğin üzerine yazar.

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

C stili dökümün aksine, statik döküm derleyicinin işaretçinin ve pointee veri türlerinin uyumlu olup olmadığını denetlemesini sağlar; bu da programcının derleme sırasında bu hatalı işaretçi atamasını yakalamasını sağlar.

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

Daha fazlası için:
static_cast <> ve C stili döküm arasındaki fark nedir
ve
Normal oyuncular vs. static_cast vs. dynamic_cast

68
Breeze

Soru, sadece static_cast veya C tarzı döküm kullanmaktan daha büyük çünkü C tarzı yayınları kullanırken ortaya çıkan farklı şeyler var. C++ döküm operatörleri bu işlemleri daha açık hale getirme amaçlıdır.

Yüzeyde static_cast ve C tarzı atmalar aynı şeye benzer, örneğin bir değeri diğerine verirken:

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

Bunların her ikisi de tamsayı değerini iki katına çıkarır. Ancak işaretçilerle çalışırken işler daha da karmaşıklaşıyor. bazı örnekler:

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

Bu örnekte (1) belki de Tamam, çünkü A ile işaret edilen nesne gerçekten B'nin bir örneğidir. Fakat ya kodun bu noktasında bir gerçekte ne anlama geldiğini bilmiyorsanız? (2) belki de tamamen yasal (tamsayının sadece bir baytına bakmak istersiniz), fakat aynı zamanda (3) gibi bir hatanın Nice olabileceği bir hata olabilir. C++ döküm işleçleri, mümkün olduğunda derleme zamanı veya çalışma zamanı hataları sağlayarak bu sorunları kodda göstermeye yöneliktir.

Yani, katı "değer döküm" için static_cast kullanabilirsiniz. Eğer çalışma zamanı polimorfik işaretçiler istiyorsa dynamic_cast kullanın. Türleri gerçekten unutmak istiyorsanız, reintrepret_cast kullanabilirsiniz. Ve sadece pencereden dışarı const atmak için const_cast var.

Sadece kodu daha açık hale getirirler, böylece ne yaptığınızı biliyormuşsunuz gibi görünür.

27
Dusty Campbell

static_cast, yanlışlıkla const_cast veya reinterpret_cast yapamayacağınız anlamına gelir, bu iyi bir şeydir.

24
DrPizza
  1. Grep veya benzeri araçlar kullanarak, kodların kodda kolayca bulunmasını sağlar.
  2. Ne tür oyuncular kullandığınızı ve derleyicinin yardımını uygulamakta zorlandığını açıkça belirtiyor. Eğer sadece uzamayı ortadan kaldırmak istiyorsanız, o zaman başka dönüştürme türlerini yapmanıza izin vermeyecek şekilde const_cast'i kullanabilirsiniz.
  3. Atışlar doğal olarak çirkin - bir programcı olarak derleyicinin normalde kodunuzu nasıl ele alacağını reddediyorsunuz. Derleyiciye "Senden daha iyisini biliyorum" diyorsun. Durum böyle olunca, bir alçı gerçekleştirmenin orta derecede acı verici bir şey olması gerektiği ve olası bir sorun kaynağı oldukları için kodunuzda yer alması gerektiği anlaşılmaktadır.

Bakınız Etkili C++ Giriş

7
JohnMcG

Bu, ne kadar güvenlik empoze etmek istediğinizle ilgilidir.

(bar) foo yazdığınızda (bir tür dönüştürme işleci sağlamadıysanız, reinterpret_cast<bar> foo işlevine eşdeğerdir), derleyiciye tür güvenliğini göz ardı etmesini ve yalnızca söyleneni yaptığınızı söylersiniz.

static_cast<bar> foo yazarken, derleyiciden en azından tür dönüşümünün mantıklı olduğunu kontrol etmesini ve integral türler için bazı dönüşüm kodları eklemesini istersiniz.


EDIT 2014-02-26

Bu cevabı 5 yıldan daha uzun bir süre önce yazdım ve yanlış anladım. (Yorumlara bakın.) Ama yine de artıyor!

7
Pitarou

i̇şaretçilerin sınıflara yönlendirilmesinin yanı sıra static_cast ayrıca sınıflarda açıkça tanımlanmış dönüşümleri gerçekleştirmek ve temel türler arasında standart dönüşümleri gerçekleştirmek için de kullanılabilir:

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

C Style kalıpları bir kod bloğunda kaçırılması kolaydır. C++ tarzı yayınlar yalnızca daha iyi bir uygulama değildir; çok daha fazla esneklik sunarlar.

reinterpret_cast, işaretçi tipi dönüşümlerin ayrılmaz bir parçasıdır, ancak yanlış kullanılırsa güvensiz olabilir.

static_cast, sayısal türler için iyi dönüşüm sağlar; numaralandırmadan girişlere veya girişlerden yüzmeye veya türden emin olduğunuz herhangi bir veri türüne kadar. Herhangi bir çalışma zamanı kontrolü yapmaz.

diğer taraftan dynamic_cast belirsiz atamaları veya dönüşümleri işaretleyen bu kontrolleri gerçekleştirir. Yalnızca işaretçiler ve referanslar üzerinde çalışır ve bir ek yüke neden olur.

Birkaç kişi daha var ama bunlar karşınıza çıkacak en önemli şeyler.

4
Konrad