Bir C ++ programı tüm istisnaları yakalamalı ve istisnaların main () bölümünden köpürmesini engellemeli midir?


29

Bir keresinde bir C ++ programının sonunda tüm istisnaları yakalaması gerektiği konusunda bilgilendirildim. O zaman verilen akıl yürütme, esasen istisnaların dışına taşmasına izin veren programların main()garip bir zombi durumuna girmesiydi. Bunu birkaç yıl önce söylemiştim ve geçmişe bakıldığında gözlemlenen olgunun, söz konusu projeden elde edilen istisnai olarak büyük çekirdek döküntülerinin uzun neslinden kaynaklandığına inanıyorum.

O zaman bu tuhaf görünüyordu ama inandırıcıydı. C ++ 'ın programcıları tüm istisnaları yakalamadıkları için "cezalandırması" tamamen saçmalıktı ancak benden önceki kanıtlar bunu destekliyor gibi görünüyordu. Söz konusu proje için, yakalanmamış istisnalar atan programlar, garip bir zombi durumuna giriyor gibi görünüyordu - ya da sebebin şimdi olduğundan şüphelendiğimde, istenmeyen bir çekirdek dökümü ortasında bir işlemi durdurmak alışılmadık bir şekilde zor.

(Bunun neden o zaman daha açık olmadığını merak eden herkes için: Proje, herhangi bir aborted (core dumped)mesaj türünü etkili bir şekilde gizleyen çoklu işlemlerde çok sayıda çıktı üretti ve bu özel durumda, çekirdek dökümlerin ölüm sonrası incelemesi yapıldı. önemli bir hata ayıklama tekniği olmadığından çekirdek döküntüler çok fazla düşünülmemişti.Bir programla ilgili sorunlar genellikle uzun süren bir program tarafından zaman içinde biriktirilen duruma değil, kısa süren bir programın ilk girdilerine bağlıdır (< 1 saat) bu nedenle, daha fazla bilgi edinmek için aynı hata ayıklama yapısındaki veya hata ayıklayıcısındaki aynı girişlerle bir programı yeniden çalıştırmak daha pratikti.)

Şu anda, istisnaları tamamen engellemek amacıyla istisnaları yakalamanın büyük bir avantajı veya dezavantajı olup olmadığından emin değilim main().

İstisnaların geçmişte kabarmasına izin verebileceğim için düşünebildiğim küçük avantaj main(), sonucun std::exception::what()terminale yazdırılmasına neden olmasıdır (en azından Linux'ta gcc derlenmiş programlarla). Öte yandan, bu yerine türetilen tüm özel durumları yakalamak oluşturulamayan önemsiz olduğunu std::exceptionve sonucunu baskı std::exception::what()ve elde edilmemiş ise bir istisna gelen bir iletiyi yazdırmak için arzu varsa std::exceptiono zaman gerekir ayrılmadan önce yakalanmış main()baskı için mesaj.

İstisnaların geçmişte kabarmasına izin vermek için düşünebildiğim en mütevazı dezavantaj main(), istenmeyen çekirdek döküntülerinin üretilebilmesidir. Çok miktarda bellek kullanan bir işlem için bu oldukça rahatsız edici olabilir ve bir programdan çekirdek boşaltma davranışını kontrol etmek, işletim sistemine özgü işlev çağrıları gerektirir. Diğer taraftan, eğer bir çekirdek dökümü ve çıkışı istenirse, bunun yerine herhangi bir zamanda çağırarak elde edilebilir std::abort()ve çekirdek dökümü olmayan bir çıkış, herhangi bir zamanda çağırarak elde edilebilir std::exit().

Önceden what(): ..., çökme üzerine yaygın olarak dağıtılan bir program tarafından basılan varsayılan mesajı hiç görmedim sanmıyorum .

Varsa, C ++ istisnalarının geçmişe doğru kabarmasına izin verilmesi konusundaki güçlü argümanlar main()nelerdir?

Düzenleme: Bu sitede çok sayıda genel istisna sorun var. Sorum özellikle işlenemeyen ve başaramayacağı özel durumlar olan C ++ ile ilgili main()- belki bir hata mesajı basılabilir, ancak bu hemen gösterme durma hatasıdır.




@gnat Sorum biraz daha belirgin. Herhangi bir programlama dilinde herhangi bir koşulda istisna işleme yerine ele alınamayan C ++ istisnaları ile ilgilidir.
Praxeolitic

Çok iş parçacıklı programlar için, işler daha karmaşık veya daha egzotik olabilir (istisnalar hariç)
Basile Starynkevitch

1
Ariane 5'in yazılımı, kesinlikle ilk lansman sırasında tüm istisnaları yakalamalarını
Eric Towers,

Yanıtlar:


25

İstisnaların ana yoldan gitmesine izin vermenin bir sorunu, programın std::terminatevarsayılan davranışın çağrılacağı bir çağrı ile biteceği yönündedir std::abort. Bu, sadece çağrılmadan önce istif açma işleminin yapılması durumunda tanımlanır , terminateböylece programınız tek bir yıkıcı çağırmadan sona erebilir! Bir yıkıcı çağrı tarafından restore edilmesi gereken bir kaynağınız varsa, zor durumdasınızdır ...


12
Bir yıkıcı çağrı tarafından restore edilmesi gereken bir kaynağınız varsa, zor durumdasınız ... => (Maalesef) C ++ 'ın çökmeye eğilimli olduğu ve bu durumun OS'nin öldürmeye karar verebileceğinden bahsetmediğinden Programınızın herhangi bir zamanda (örneğin, Unix’deki OOM katili), programınızın (ve onun ortamının) çökmeleri desteklemek için uyarlanması gerekir.
Matthieu M.

@MatthieuM. Yıkıcıların kaza sırasında bile oluşacak kaynak temizliği için uygun bir yer olmadığını mı söylüyorsunuz?
Praxeolitic,

6
@Praxeolitic: Diyelim ki tüm çökmeler yığını istiflemiyor, mesela std::abortyok ve bu yüzden başarısız iddialar da yok. Ayrıca, modern işletim sistemlerinde, işletim sisteminin kendisinin işlem kimliğine bağlı birçok kaynağı (bellek, dosya tanıtıcıları ...) temizleyeceğini de belirtmek faydalı olacaktır. Son olarak, “Derinlikteki Savunma” yı da ima ediyordum: diğer tüm işlemlerin hatalara karşı korumalı olmasını beklediğinizden emin değilsiniz ve edindikleri kaynakları (oturumlar, güzelce yazmayı bitirmek gibi…) her zaman planlamanız gerekir. o ...
Matthieu M.

3
@Praxeolitic Hayır, yazılımınızın bir elektrik kesintisi sırasında verileri bozmaması gerekir . Bunu yönetebilirseniz, işlenmeyen bir istisnadan sonra verilerin bozulmamasını da sağlayabilirsiniz.
user253751

1
@Praxeolitic: Aslında, bu var. WM_POWERBROADCASTMesajı dinlemek isteyeceksiniz . Bu yalnızca bilgisayarınız pille çalışıyorsa çalışır (bir dizüstü bilgisayar veya UPS kullanıyorsanız).
Brian,

28

İstisnaların kaçmamasına sebep olmasının temel nedeni main, aksi halde sorunun kullanıcılarınıza nasıl rapor edileceğini kontrol etme olasılığını kaybetmenizdir.

Uzun süre kullanılması amaçlanmayan veya yaygın olarak dağıtılmayan bir program için, işletim sisteminin yapmaya karar verdiği şekilde beklenmedik hataların bildirilmesi kabul edilebilir (örneğin, Windows’da bir yüzyüze hata iletişim kutusu gösteriliyorsa) ).

Sattığınız veya genel olarak kamuya sağladığı ve sürdüreceği bir kuruluş tarafından sağlanan programlar için, beklenmedik bir sorunla karşılaştığınız ve tasarruf etmeyi denediğinizden daha iyi bir şekilde rapor etmek genellikle daha iyi bir fikirdir. kullanıcının verileri mümkün olduğunca. Kullanıcınızın yarım günlük çalışmasını kaybetmemek ve beklenmedik şekilde çökmemek, ancak yarı incelikle kapatmak genellikle iş ününüz için alternatiflerden çok daha iyidir.


Bir C ++ istisnasının varsayılan davranışının main() işletim sistemi ile ilgisi olduğundan emin misiniz ? İşletim sistemi C ++ hakkında hiçbir şey bilmiyor olabilir. Tahminim, derleyicinin programın herhangi bir yerine koyduğu kodla belirlenmesiydi.
Praxeolitic,

5
@Praxeolitic: İşletim sisteminin kuralları belirlemesi daha fazla ve bir program beklenmedik bir şekilde sona erdiğinde derleyici bu kuralları yerine getirmek için kod üretir. Sonuç olarak, makul bir şekilde mümkün olduğunda beklenmeyen program sonlandırmalarından kaçınılması gerektiğidir.
Bart van Ingen Schenau

Sadece std C ++ kapsamındaki kontrolü kaybedersiniz. Bu tür "çökmeler" ile başa çıkmak için uygulamaya özel bir yöntem mevcut olmalıdır. C ++ genellikle vakumda çalıştırılmaz.
Martin Ba

Yüzünüzdeki hata iletişim kutusu, kayıt defterinde neye mal olursa olsun açık / kapalı olarak yapılandırılabilir - ancak bunun için kayıt defterinin kontrolüne ihtiyacınız olacaktır - ve çoğu program kiosk modunda çalışmıyor (devralınmakta) işletim sistemi).
PerryC,

11

TL; DR : Şartname ne diyor?


Teknik bir servis yolu ...

Bir istisna atıldığında ve hiçbir işleyici bunun için hazır olmadığında:

  • yığının çözülüp çözülmeyeceği tanımlanmış bir uygulamadır
  • std::terminate varsayılan olarak iptal edilen
  • ortam kurulumunuza bağlı olarak, iptal, geride bir kilitlenme raporu bırakabilir veya bırakmayabilir.

Sonuncusu çok nadir görülen hatalar için faydalı olabilir (çünkü bunların çoğaltılması zaman kaybettirici bir işlemdir).


Tüm istisnaları yakalayıp yakalamama, nihayetinde bir şartname meselesidir:

  • hatalarının nasıl bildirileceği belirtildi mi? (geçersiz değer, ...)
  • hatalarının nasıl bildirileceği belirtildi mi? (hedef dizin eksik, ...)
  • teknik hataların nasıl bildirileceği belirtildi mi? (iddia ateşleniyor, ...)

Herhangi bir üretim programı için, bu belirtilmeli ve şartnameye uymalısınız (ve belki de değişmiş olabilir).

Hızlı bir şekilde birlikte atılan programları sadece teknik kişiler (siz, takım arkadaşlarınız) kullanın. Gereksinimlerinize bağlı olarak bir rapor alıp vermeyecek şekilde çökmesine ve ortamı ayarlamasına izin vermenizi öneririm.


1
Bu. Karar faktörleri wrt. Temelde C ++ kapsamı dışındadır.
Martin Ba

4

Yakaladığınız bir istisna size güzel bir hata mesajı basma veya hatadan kurtulmayı deneme imkanı verir (muhtemelen sadece uygulamayı yeniden başlatarak).

Ancak, C ++ 'da bir istisna, atıldığı zaman programın durumu hakkında bilgi içermez. Onu yakalarsanız, bu tür durumların tümü unutulur, oysa programın çökmesine izin verirseniz, durum genellikle hala oradadır ve program dökülmesinden okunabilir ve bu da hata ayıklamayı kolaylaştırır.

Yani bu bir takas.


4

Bildiğiniz an iptal etmek zorundasınız, devam edin ve std::terminatedaha fazla hasarı azaltmak için zaten arayın .

Güvenli bir şekilde aşağı inebileceğinizi biliyorsanız, bunu yapın. Bir istisna asla yakalanmadığında istifin çözülmesinin garanti edilmediğini unutmayın.

Hatayı, sistemin kendi başına yapabileceğinden daha iyi güvenli bir şekilde raporlayabilir / günlüğe kaydedebiliyorsanız, devam edin.
Ancak istemeden, meseleleri yanlışlıkla yaparken daha da kötüleştirmemeye dikkat edin.

Belirli bir hataya bağlı olmasına rağmen, kurtarılamaz bir hata tespit ettiğinizde veri kaydetmek için genellikle çok geç.
Neyse, programınız hızlı kurtarma için yazılmışsa, sadece normal bir kapatma bile olsa onu sonlandırmanın en iyi yolu olabilir.


1

Nazikçe çarpmak çoğu zaman iyi bir şeydir - ancak takaslar vardır. Bazen çökmesi iyi bir şeydir. Çok fazla hata ayıklamayı düşündüğümü söylemeliyim. Basit bir program için - bu yine de faydalı olsa da, çok karmaşık bir programla (ya da birbiriyle etkileşime giren birkaç karmaşık programla) olduğu kadar yardımcı olamaz.

Toplum içinde çarpmak istemezsiniz (bu gerçekten kaçınılmaz olsa da - programlar çöküyor ve gerçekten matematiksel olarak doğrulanabilir çökmeyen bir program burada bahsettiğimiz şey değil). Bill Gates'i düşünün BSODing'in ortasında bir demo - kötü, değil mi? Bununla birlikte, neden aynı şekilde çarptığımızı ve çarpmadığımızı anlamaya çalışabiliriz.

İşlenmeyen istisnalar üzerinde yerel çökme dökümü oluşturan Windows Hata Bildirimi özelliğini açtım. (Çöken) yapınızla ilişkili sembol dosyalarınız varsa harikalar yaratır. İlginçtir, çünkü bu aracı kurduğum için daha fazla çarpmak istiyorum - çünkü her çarpışmadan ders alıyorum. O zaman hataları düzeltip daha az çarpabilirim.

Şimdilik programlarımın en üste fırlatıp çökmesini istiyorum. Gelecekte, tüm istisnalarımı zarif bir şekilde yemek isteyebilirim - ama onları benim için çalışmasını sağlayamazsam.

Yerel Crash Dumps hakkında daha fazla bilgiyi burada bulabilirsiniz: Kullanıcı Modu Dökümü Toplama


-6

Sonuçta, eğer bir istisna main () 'i geçerse, uygulamanızı çökertir ve bence bir uygulama asla çökmemelidir. Bir uygulamayı bir yerde çökertmek uygunsa, neden olmasın? Neden istisna işlemleriyle uğraşmıyorsun? (Alaycılık, bunu gerçekten önermiyor ...)

Kullanıcıya, onarılamaz bir hata oluştuğunu ve BT ile ilgili bir haber ya da benzeri bir şey için e-posta göndermeleri gerektiğini söyleyen zarif bir mesaj yazdıran küresel bir deneme / yakalama olabilir, ancak çarpma tamamen profesyonelce ve kabul edilemez. Önlemek için önemsizdir ve bir kullanıcıyı yeni neler olduğu ve olayları nasıl düzeltebileceği konusunda bilgilendirebilirsiniz.

Çarpma kesinlikle amatör saattir.


8
Öyleyse, her şey yolundaymış gibi davranmak daha iyi ve bunun yerine anlamsız saklamak yerine tüm kalıcı depolamanın üzerine yazmak?
Deduplicator

1
@Deduplicator: Hayır: istisnayı her zaman yakalayabilir ve halledebilirsiniz.
Giorgio

5
Nasıl başa çıkacağını biliyorsanız, muhtemelen kalkmadan çok önce başa çıkacaksınız main. Bununla nasıl başa çıkacağınızı bilmiyorsanız, yaptığınız gibi davranmak gerçekten de korkunç bir hatadır.
Deduplicator

8
ancak çökme tamamen profesyonelce ve kabul edilemez => işe yaramaz özellikler üzerinde çalışmak için zaman harcamak profesyonelce yapılmaz: yalnızca son kullanıcı için önemliyse, eğer yapmazsa, o zaman çökmesine izin vererek (ve bir bellek dökümü ile çarpışma raporunu alır) önemli olanı çökertmek daha ekonomiktir.
Matthieu M.

Matthieu M. gerçekten bir hata kaydı yapmak, açık dosyaları kaydetmek ve ekranda dostça bir mesaj boyamak için ne kadar çaba sarf ediyorsa, ne diyeceğimi bilemiyorum. Eğer inceliksizce başarısız olmanın faydasız olduğunu düşünüyorsanız, muhtemelen kodunuz için teknik destek yapan kişiyle konuşmalısınız.
Roger Hill
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.