Neden 'void *', C ++ 'da örtük olarak kullanılmıyor?


30

C'de, void *herhangi bir işaretçi tipine bir a kullanmaya gerek yoktur , her zaman güvenli bir şekilde teşvik edilir. Ancak, C ++, bu durum böyle değil. Örneğin,

int *a = malloc(sizeof(int));

C ile çalışır, ancak C ++ ile çalışmaz. (Not: mallocC ++ 'da veya bu konuda newkullanmamanız gerektiğini ve bunun yerine akıllı göstericileri ve / veya STL'yi tercih etmeniz gerektiğini biliyorum ; bu tamamen meraktan sorulur.) C ++ standardı neden bu gizli kullanıma izin vermiyor? C standardı ne zaman?


3
long *a = malloc(sizeof(int));Hata! Birisi sadece bir tip değiştirmeyi unuttu!
Doval

4
@Doval: Bunun sizeof(*a)yerine hala kolayca düzeltilebilir .
wolfPack88

3
@ Ratchetfreak'in amacının, C'nin bu örtük dönüştürmeyi yapmasının sebebinin malloc, tahsis edilen tipe bir gösterici döndürememesi olduğuna inanıyorum . newC ++, atanan türe bir gösterici döndürür, bu yüzden doğru yazılmış C ++ kodunu kullanmak için hiçbir zaman void *s yazmaz .
Robotu

3
Bir kenara, başka herhangi bir işaretçi türü değil. Sadece veri işaretçilerine ihtiyaç vardır.
Deduplicator

3
@ wolfPack88 tarihin yanlış. C ++ vardı voidC yaptım değil . Söz konusu anahtar kelime / fikri C'ye ilave edildiğinde bunlar C'nin ihtiyaçlarına uygun şekilde değiştirdi. İşaretçi tipleri kontrol başlandı sonra bu kısa bir süre oldu hiç . Çevrimiçi K&R C tanıtım broşürünü veya Waite Group'un C Astarı gibi bir C programlama metninin eski bir kopyasını bulabilecek misiniz bir bakın . ANSI C doluydu, C ++ tarafından desteklenen ya da esinlenilen özellikler ve K&R C çok daha kolaydı. Bu nedenle, C ++ 'ın o anda C olduğu kadar genişledi ve bildiğiniz C ise C ++' dan çıkarıldı.
JDługosz

Yanıtlar:


39

Örtük tip dönüşümler genellikle güvensizdir ve C ++ yazarak C'den daha güvenli bir duruş sergiler.

C, çoğu zaman dönüşümün bir hata olduğu durumlarda bile, örtük dönüşümlere izin verir. Çünkü C programcının tam olarak ne yaptığını bildiğini varsayar ve eğer değilse, programcının problemidir, derleyicinin problemi değil.

C ++ genellikle potansiyel olarak hata olabilecek şeylere izin vermez ve niyetinizi bir tür cast ile açıkça belirtmenizi ister. Çünkü C ++ programcı dostu olmaya çalışıyor.

Daha fazla yazmaya başlamanızı gerçekten gerektirdiğinde, nasıl bir arkadaşlık olduğunu sorabilirsiniz.

Eh, görüyorsunuz, herhangi bir program dilinde, herhangi bir program dilinde herhangi bir kod satırı genellikle yazıldığından çok daha fazla okunacaktır (*). Bu nedenle, okuma kolaylığı yazma kolaylığından çok daha önemlidir. Ve okurken, potansiyel olarak güvensiz dönüşümlerin açık tip yayınlar ile göze çarpması, neler olup bittiğini anlamaya ve ne olduğunun gerçekte ne olduğuna dair kesin bir kesinliğe sahip olmaya yardımcı olur.

Ayrıca, açık oyuncu kadrosunu yazmanın zorluğu, sizi uyarmış olabileceğiniz, ancak asla olamadığınız yanlış bir görevin yol açtığı bir hatayı bulmak için saatlerce süren sorun giderme ile ilgili saatlerin uygunsuzluğuyla karşılaştırıldığında önemsizdir.

(*) İdeal olarak, sadece bir kez yazılır, ancak her biri yeniden kullanım için uygunluğunu belirlemek için incelemeye ihtiyaç duyduğu her zaman ve ne zaman sorun giderilirse ve birisinin yanına kod eklemesi gerektiğinde okunur. ve sonra her zaman yakın kodda sorun giderme vb. Bu, "bir kez yaz, koş, sonra fırlat" komutları dışında tüm durumlarda doğrudur ve bu nedenle çoğu komut dosyası dilinin, okuma kolaylığını tamamen ihmal ederek yazmayı kolaylaştıran bir sözdizimine sahip olması şaşırtıcı değildir. Perl'in tamamen anlaşılmaz olduğunu hiç düşündün mü? Yalnız değilsin. "Yalnızca yaz" dilleri gibi dilleri düşünün.


C esasen makine kodunun üstündeki bir adımdır. Böyle şeylerden dolayı C’yi affedebilirim.
Qix

8
Programlar (dil ne olursa olsun) okunması amaçlanmıştır. Açık işlemler göze çarpıyor.
Matthieu M.

10
It yetmeyecek yoluyla atmalarını olduğunu, belirterek void*vardır daha çünkü belirli cepten özellikleri C uygulanma şekliyle ile C ++ güvensiz ++, aynı nesneye işaretçi işaretçi türüne bağlı olarak farklı değer bulunabilir.
Hyde

@MatthieuM. çok doğru. Bunu eklediğiniz için teşekkürler, cevabın bir parçası olmaya değer.
Mike Nakis

1
@MatthieuM .: Ah, ama gerçekten her şeyi açıkça yapmak istemezsiniz. Okunabilirlik, daha fazla okuyarak elde edilemez. Her ne kadar bu noktada denge açık olduğu açıktır.
Deduplicator

28

İşte Stroustrup ne diyor :

C'de, bir boşluğu * örtülü olarak bir T * biçimine dönüştürebilirsiniz. Bu güvensiz

Daha sonra, boşluğun * ne kadar tehlikeli olabileceğinin bir örneğini göstermeye devam ediyor ve şöyle diyor:

... Sonuç olarak, C ++ 'da bir boşluktan * T * almak için açık bir döküm yapmanız gerekir. ...

Sonunda, notları:

Bu güvenli olmayan dönüştürmenin C'deki en yaygın kullanımlarından biri, malloc () sonucunu uygun bir göstericiye atamaktır. Örneğin:

int * p = malloc (sizeof (int));

C ++ 'da typesafe new operatörünü kullanın:

int * p = yeni int;

C ++ 'ta Tasarım ve Evrim'de bu konuda daha fazla ayrıntıya giriyor .

Böylece cevap şunun için aşağıya düşer: Dil tasarımcısı, güvensiz bir model olduğuna inanır ve bu nedenle yasadışı yapılmasını sağlar ve modelin normalde ne için kullanıldığını yerine getirmenin alternatif yollarını sunar.


1
Örneğe göre, yapıcı olarak adlandırmayacağının (açıkça) bir not çıkarmayacağına mallocdikkat çekmek gerekir; mallocbu nedenle, eğer hafıza için ayırdığınız bir sınıf tipi ise, sınıf tipine örtük olarak kullanabilmek yanıltıcı olacaktır.
chbaker0

Bu çok iyi bir cevap, tartışmasız benimkinden daha iyi. Sadece "otorite argümanı" yaklaşımını beğenmedim.
Mike Nakis

"yeni int" - vay, bir C ++ acemi olarak, yığına bir temel türü eklemenin bir yolunu düşünmekte zorlanıyordum ve bunu yapabileceğinizi bile bilmiyordum. Malloc için -1 kullanımı.
Katana314

3
@MikeNakisFWIW, niyetim cevabınızı tamamlamaktı. Bu durumda, soru "neden bunu yaptılar" idi, bu yüzden baş tasarımcının haberinin haklı olduğunu düşündüm.
Robot'a

11

C'de, herhangi bir diğer işaretçi tipine boşluk * koymaya gerek yoktur, her zaman güvenli bir şekilde yükseltilir.

Her zaman terfi ettirilir, evet ama zor bir şekilde .

C ++ bu davranışı tam olarak devre dışı bırakır, çünkü C'den daha güvenli bir tür sistemine sahip olmaya çalışır ve bu davranış güvenli değildir .


Genel olarak aşağıdaki 3 dönüşüm türünü ele aldığınızı düşünün:

  1. kullanıcıyı her şeyi yazmaya zorlar, böylece tüm dönüşümler açıktır
  2. Kullanıcının ne yaptığını bildiğini varsayalım ve herhangi bir türü diğerine dönüştürün
  3. güvenli tip jenerik (şablonlar, yeni ifadeler), açık kullanıcı tanımlı dönüşüm operatörleri ile tam bir tür sistem uygulayın ve yalnızca derleyicinin göremediği şeylerin açıkça dönüştürülmesini zorunlu kılın

Eh, 1 çirkin ve bir şeyi yapmanın önündeki pratik bir engel, ancak gerçekten çok dikkatli olunması gerektiğinde kullanılabilir. C, kabaca 2'nin daha kolay, ancak uygulanması daha kolay olan C ++ 'ı tercih etti.


Daha sonra eklenen istisnalar ve daha sonra hala şablonlarla birlikte, 3'e ulaşmak çok zor bir yoldu.
JDługosz

Eh, bu tür güvenli bir sistem için şablonlara gerçekten ihtiyaç duyulmuyor : Hindley-Milner tabanlı diller oldukça iyi anlaşıyorlar, örtük dönüşümler olmadan da açıkça yazabiliyorlar. (Tabii ki, bu diller C ++ 'ın kaçındığı şeylere silme / çöp toplama / yüksek-tür polimorfizmine dayanmaktadır.)
leftaroundabout 10:15

1

Tanım olarak, boş bir işaretçi herhangi bir şeye işaret edebilir. Herhangi bir işaretçi boş işaretçiye dönüştürülebilir ve böylece geri gelen aynı değerde geri dönüştürebilirsiniz. Ancak, diğer türlere yönelik işaretçilerin hizalama kısıtlamaları gibi kısıtlamaları olabilir. Örneğin, karakterlerin herhangi bir hafıza adresini işgal edebileceği, ancak tamsayıların adres sınırlarında bile başlaması gereken bir mimari düşünün. Bazı mimarilerde, tamsayı işaretçiler bir seferde 16, 32 veya 64 bit sayarlar, böylece bir karakter * aslında bellekte aynı yere işaret ederken int * 'nin sayısal değerinin bir katına sahip olabilir. Bu durumda, bir boşluktan * dönüştürme aslında kurtarılamayan ve bu nedenle geri dönüşü olmayan bitleri tamamlar.

Basitçe söylemek gerekirse, boşluk işaretçisi, diğer işaretçilerin işaret edemeyeceği şeyler dahil, herhangi bir şeyi işaret edebilir. Bu nedenle, boş göstericiye dönüştürme güvenlidir, ancak tersi olmaz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.