İstisna spesifikasyonları neden kötü?


50

Yaklaşık 10 yıl önce okula geri döndüğünde, size istisna belirtecilerini kullanmayı öğretiyorlardı. Geçmişim onlardan biri olduğu için zorlamadıkça inatla C ++ 'dan kaçınan Torvaldish C programcıları olduğu için, sadece sporadik olarak sadece C ++' a giriyorum ve bunu yaptığımda hala istisna belirtecilerini kullanıyorum.

Bununla birlikte, C ++ programcılarının çoğunluğu istisna belirleyicileri üzerine kaşlarını çatıyor gibi görünüyor. Tartışmayı ve çeşitli C ++ gurularının argümanlarını okudum, bunun gibi . Anladığım kadarıyla, üç şeye kadar kaynar:

  1. İstisna belirticileri, dilin geri kalanıyla tutarsız olan bir tür sistemi kullanır ("gölge tür sistemi").
  2. Bir istisna belirteci olan işleviniz, sizin belirttiğiniz dışında başka bir şey atarsa, program kötü, beklenmedik şekillerde sonlandırılır.
  3. İstisna belirteçleri yaklaşmakta olan C ++ standardında kaldırılacak.

Burada bir şey mi eksik veya tüm nedenler bunlar mı?

Kendi görüşlerim:

1): Peki ne olmuş. C ++ muhtemelen şimdiye kadar yapılmış en tutarsız programlama dilidir, sözdizimi açısından. Makrolar, genel / etiketler, tanımlanmamış / belirtilmemiş / / uygulama-tanımlanmış davranışların belirsizliği (hoard?), İyi tanımlanmamış tamsayı türleri, tüm kapalı tip promosyon kuralları, arkadaş, oto gibi özel durumlu anahtar kelimelerimiz var. , kayıt ol, açık ... Ve benzeri. Birileri muhtemelen C / C ++ 'da tuhaflıktan birkaç kalın kitap yazabilir. Öyleyse insanlar neden dilin çok daha tehlikeli özelliklerine kıyasla küçük bir kusur olan bu özel tutarsızlığa karşı tepki gösteriyorlar?

2 ile ilgili olarak): Bu benim sorumluluğum değil mi? C ++ 'da ölümcül bir hata yazabileceğim başka birçok yol var, bu özel durum neden daha da kötü? throw(int)Yazmak ve sonra Crash_t'yi atmak yerine, işlevimin int için bir işaretçi döndürdüğünü, sonra da vahşi, açık bir typecast oluşturup bir işaretçiyi Crash_t'ye döndürdüğünü iddia edebilirim. C / C ++ 'ın ruhu her zaman sorumluluğun çoğunu programlayıcıya bırakmak olmuştur.

Peki ya avantajlar? En açık olanı, eğer fonksiyonunuz açıkça belirttiğinizden başka bir tür atmaya çalışırsa, derleyici size bir hata verecektir. Standardın bu konuda açık olduğuna inanıyorum (?). Hatalar, yalnızca fonksiyonunuz, sırayla yanlış tipi atan diğer fonksiyonları çağırdığında ortaya çıkar.

Deterministik, gömülü C programları dünyasından gelince, bir fonksiyonun bana ne atacağını kesinlikle bilmeyi tercih ederim. Dilde bunu destekleyen bir şey varsa, neden kullanmıyorsunuz? Alternatifler gibi görünüyor:

void func() throw(Egg_t);

ve

void func(); // This function throws an Egg_t

Sanırım, arayan kişinin ikinci durumda denemeyi uygulamaya koymasını görmezden gelmesi / unutması gibi büyük bir şans olduğunu düşünüyorum.

Anladığım kadarıyla, bu iki formdan biri aniden başka bir istisna yaratmaya karar verirse, program çökecektir. İlk durumda, başka bir istisna atmasına izin verilmediğinden, ikinci durumda, hiç kimse bir SpanishInquisition_t atmayı beklememesi nedeniyle ve bu nedenle ifadesi olması gerektiği yerde yakalanmadı.

İkincisi durumunda, programın en üst seviyesinde son çare avı (...) yapmak gerçekten bir programın çökmesinden daha iyi görünmüyor: "Hey, programınızın herhangi bir yerinde garip, işlenmeyen bir istisna attı . ". İstisnanın atıldığı yerden uzakta olduğunuzda programı kurtaramazsınız, yapabileceğiniz tek şey programdan çıkmaktır.

Ve kullanıcının bakış açısından, işletim sisteminden "Program sonlandı. 0x12345 adresinde Blablabla" diyen kötü bir mesaj kutusu veya "İşlenmeyen istisna: myclass" yazan programınızdan kötü bir mesaj kutusu alırsa daha az umursayamazlardı. func.something". Böcek hala orada.


Yaklaşan C ++ standardı ile istisna belirteçlerini terk etmekten başka seçeneğim kalmayacak. Ancak "Kutsal Hazretleri bunu belirtti ve bu yüzden öyle" yerine, neden kötü olduklarına dair sağlam bir argüman duymayı tercih ederim. Belki de onlara karşı listelediklerimden daha fazla argüman var veya belki de benim düşündüğümden daha fazla var?


30
Bunu "rant, soru kılık değiştirmiş" olarak oy kullanmaya teşvik ediyorum. E.specs hakkında üç geçerli nokta soruyorsunuz, fakat neden bizi C ++ - çok can sıkıcı ve ben gibi daha iyi huysuzluklarla rahatsız ediyorsunuz?
Martin Ba,

10
@Martin: Çünkü hem önyargılı olduğumu hem de tüm ayrıntılara ayak uyduğumu değil, aynı zamanda dili saf ve / veya henüz mahvetmemiş gözlerle de gördüğümü belirtmek istiyorum. Ancak, C ve C ++ 'nın zaten inanılmaz derecede kusurlu dilleri olduğu için, bir veya daha fazla kusurun önemi yok. Yazı ben onu düzenlemeden önce aslında çok daha kötüydü :) İstisna belirleyicilere karşı olan argümanlar da oldukça özneldir ve bu yüzden öznelleşmeden onları tartışmak zordur.

SpanishInquisition_t! Neşeli! Ben şahsen istisnaları atmak için yığın çerçeve göstergesinin kullanılmasından etkilendim ve kodu daha temiz hale getirecek gibi görünüyor. Ancak, hiçbir zaman istisnalar dışında kod yazmadım. Bana eski moda diyoruz, ancak geri dönüş değerleri benim için iyi sonuç veriyor.
Shahbaz

@Shahbaz Biri satırlar arasında okuyabildiği gibi, ben de oldukça eski kafalıyım ama yine de aslında istisnaların kendi başlarına mı yoksa kötü mü olduğunu asla sorgulamadım.

2
Gergin geçmiş atmak olduğunu attı , değil throwed . Bu güçlü bir fiil.
TRiG

Yanıtlar:


48

İstisna özellikleri kötüdür, çünkü zayıf bir şekilde uygulanırlar ve bu yüzden aslında çok fazla bir şey yapmazlar ve aynı zamanda UB'yi çağırmak yerine () sonlandırmak için beklenmedik istisnaları kontrol etmek için çalışma zamanını zorladıkları için de kötüdürler. bu, önemli miktarda performansı israf edebilir.

Sonuç olarak, istisna özellikleri, kodu gerçekten daha güvenli hale getirecek dilde yeterince güçlü bir şekilde uygulanmadı ve bunları belirtilen şekilde uygulamak büyük bir performans kaybıydı.


2
Ancak çalışma zamanı kontrolü, istisna şartnamesinin hatası değil, yanlış tür atılırsa standardın hangi kısmının sona ermesi gerektiğini belirtir. Bu dinamik kontrole giden gereksinimi basitçe ortadan kaldırmak ve her şeyin derleyici tarafından statik olarak değerlendirilmesine izin vermek akıllıca olmaz mıydı? Görünüşe göre RTTI buradaki gerçek suçlu mu, yoksa ...?

7
@Lundin: C ++ 'da bir fonksiyondan atılabilecek tüm istisnaları statik olarak belirlemek mümkün değildir, çünkü dil çalışma zamanında kontrol akışında keyfi ve deterministik olmayan değişikliklere izin verir (örneğin fonksiyon işaretçileri, sanal yöntemler ve gibi). Java gibi statik derleme zamanı istisnası uygulamak, dilde temel değişiklikler ve devre dışı bırakılması için çok fazla C uyumluluğu gerektirecektir.

3
@OrbWeaver: Statik kontrollerin oldukça mümkün olduğunu düşünüyorum - istisna spesifikasyonu bir fonksiyonun spesifikasyonunun bir parçası olurdu (dönüş değeri gibi) ve fonksiyon işaretçileri, sanal geçersiz kılmalar vb. Uyumlu özelliklere sahip olmalıdır. Asıl itiraz, tamamen ya da hiç özelliğinin olmamasıydı - statik istisna özelliklerine sahip işlevler, eski işlevleri çağıramadı. (C işlevlerini çağırmak iyi olmaz, çünkü hiçbir şey atamazlar).
Mike Seymour

2
@ Lundin: İstisna özellikleri kaldırılmadı, kullanımdan kaldırıldı. Bunları kullanan eski kod hala geçerli olacak.
Mike Seymour

1
@ Lundin: C ++ 'ın eski sürümleri istisna özellikleriyle mükemmel uyumludur. Kod daha önce geçerliyse, ne derleyemedi ne de beklenmedik bir şekilde çalışmayacaklar.
DeadMG

18

Hiç kimsenin onları kullanmamasının bir nedeni, temel varsayımınızın yanlış olmasıdır:

“En açık [avantaj], işleviniz açıkça belirttiğinizden başka bir tür atmaya çalışırsa, derleyici size bir hata verecektir.”

struct foo {};
struct bar {};

struct test
{
    void baz() throw(foo)
    {
        throw bar();
    }
};

int main()
{
    test x;
    try { x.baz(); } catch(bar &b) {}
}

Bu program hiçbir hata veya uyarı içermez .

Ayrıca, istisna yakalanmış olsa bile , program hala sona ermektedir.


Düzenleme: Sorunuzdaki bir noktaya cevap vermek için, catch (...) (veya daha iyisi, catch (std :: exeption &) veya diğer temel sınıf ve ardından catch (...)) yapmasanız bile yine de kullanışlıdır. Neyin yanlış gittiğini tam olarak bil.

Kullanıcınızın "kaydet" için bir menü düğmesine bastığını düşünün. Menü düğmesinin işleyicisi, uygulamayı kaydetmeye davet eder. Bu sayısız nedenden ötürü başarısız olabilir: dosya yok olan bir ağ kaynağındaydı, salt okunur bir dosya vardı ve kayıt edilemiyordu, vb. Ancak işleyici bir şeyin neden başarısız olduğunu gerçekten umursamıyor; sadece başarılı veya başarısız olmasını umursar. Eğer başarırsa, her şey yolunda. Başarısız olursa, kullanıcıya söyleyebilir. İstisnanın kesin yapısı alakasızdır. Ayrıca, uygun ve istisnai güvenli bir kod yazarsanız, bu tür herhangi bir hatanın sisteminizi çökertmeden ilerletebileceği anlamına gelir - hatayı umursamayan kodlar için bile. Bu, sistemi genişletmeyi kolaylaştırır. Örneğin, şimdi bir veritabanı bağlantısı aracılığıyla kaydedersiniz.


4
O derlenmiş @Lundin olmadan uyarılar. Ve hayır, yapamazsın. Güvenilir değil. İşlev işaretçilerinden çağırabilir veya sanal üye işlevi olabilir ve türetilmiş sınıf, tür_exception (temel sınıfın muhtemelen bilmediği) atar.
Kaz Ejderha

Zor şans. Embarcadero / Borland bunun için bir uyarı veriyor: "istisna belirteci ihlalini istisna atama". Görünüşe göre GCC değil. Yine de bir uyarı verememelerinin bir nedeni yok. Benzer şekilde, statik bir analiz aracı bu hatayı kolayca bulabilir.

14
@ Lundin: Lütfen yanlış bilgileri tartışmaya ve tekrarlamaya başlamayın. Sorunuz zaten bir ranttan ibaretti ve yanlış şeyler iddia etmek işe yaramıyor. Bir statik analiz aracı bunun gerçekleşip gerçekleşmeyeceğini tespit edemez; bunu yapmak Halting Problemini çözmeyi gerektirir. Ayrıca, tüm programı analiz etmesi gerekecektir ve çoğu zaman tüm kaynak mevcut değildir.
David Thornley

1
@Lundin aynı statik analiz aracı size hangi atılan istisnaların yığınızdan ayrıldığını söyleyebilir, bu durumda istisna spesifikasyonlarını kullanmak hala hata durumuyla başa çıkabileceğiniz programınızı aşağıya çekecek olası bir negatif negatif dışında size hiçbir şey satın almaz. çok daha güzel bir yol (örneğin, hatayı duyurmak ve koşmaya devam etmek gibi: örneğin, cevabımın ikinci yarısına bakınız).
Kaz Ejderha

1
@ Lundin İyi bir soru. Cevap, genel olarak, aradığınız işlevlerin istisnalar atıp atmayacağını bilmemenizdir, bu nedenle güvenli varsayım, hepsinin yaptığıdır. Bunları nerede yakalayacağım sorusu stackoverflow.com/questions/4025667/… adresinde cevapladığım bir soru . Özellikle olay işleyicileri doğal modül sınırlarını oluşturur. İstisnaların genel bir pencereye / olay sistemine (örn.) Kaçmasına izin verilmesi cezalandırılır. Program orada hayatta kalmak istiyorsa, işleyici hepsini yakalamalıdır.
Kaz Ejderha

17

Anders Hejlsberg ile yapılan bu röportaj oldukça ünlü. İçinde C # tasarım ekibinin neden ilk başta kontrol edilen istisnaları attığını açıklıyor. Özet olarak, iki ana neden vardır: sürümlenebilirlik ve ölçeklenebilirlik.

OP'nin C ++ 'ya odaklandığını biliyorum, oysa Hejlsberg C #' yı tartışıyor, ancak Hejlsberg 'in yaptığı noktalar da C ++' a mükemmel bir şekilde uygulanabilir.


5
"Hejlsberg'in yaptığı noktalar C ++ 'a da mükemmel bir şekilde uygulanabilir" .. Yanlış! Java'da uygulanan kontrol edilen istisnalar , arayan kişiyi kendisiyle (ve / veya arayan kişinin vb.) Uğraşmaya zorlar. İstisna gözlük (oldukça zayıf ve yararsız iken) sadece tek bir "fonksiyonu-call-sınır" için geçerli ve do C ++ değil "çağrı yığını yaymak" gibi istisnalar yapmak kontrol etti.
Martin Ba

3
@ Martin: C ++ 'da istisna özelliklerinin davranışına katılıyorum. Ama "Hejlsberg’in yaptığı puanlar C ++ 'a tamamen uygulanabilir" ibaresini verdiğim ifadem, Hejlsberg’in C ++ özelliklerinden ziyade yaptığı noktalara atıfta bulunuyor. Başka bir deyişle, burada istisna yayılımı yerine programın sürümlendirilebilirliği ve ölçeklenebilirliği hakkında konuşuyorum.
CesarGon

3
Hejlsberg ile oldukça erken aynı fikirde değildim: “Kontrol edilen istisnalar hakkındaki endişelerim, programcılara koydukları kelepçeler. Programcıların, tüm bu kuralları kullanan yeni API'leri seçtiklerini görüyorsunuz. kontrol edilen istisnalar onlara hiçbir şekilde yardımcı olmuyor. Bu istisna işlemlerinizi nasıl yapacağınızı söyleyen bu diktatör API tasarımcıları. --- İstisnalar kontrol ediliyor veya kontrol edilmiyor, hala aradığınız API tarafından atılan istisnaları ele almanız gerekiyor. İşaretli istisnalar açıkça onu açıkça ifade eder.
quant_dev

5
@quant_dev: Hayır, aradığınız API tarafından atılan istisnaları ele almanız gerekmez. Mükemmel bir seçenek, istisnaları ele almamak ve arayanın kullanması için çağrı yığınını kabarmalarını sağlamaktır.
CesarGon

4
@CesarGon İstisnaları dikkate almamak, aynı zamanda bunların nasıl kullanılacağı konusunda bir seçimdir.
quant_dev
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.