İstisna işlemeyi ne zaman ve nasıl kullanmalıyım?


83

İstisna işlemeyi okuyorum. İstisna işlemenin ne olduğu hakkında biraz bilgi aldım, ancak birkaç sorum var:

  1. Ne zaman bir istisna yapılmalı?
  2. Bir istisna atmak yerine, hatayı belirtmek için bir dönüş değeri kullanabilir miyiz?
  3. Tüm fonksiyonlarımı deneme-yakalama bloklarıyla korursam, performansı düşürmez mi?
  4. İstisna işleme ne zaman kullanılır?
  5. Bu projedeki her işlevin bir dene-yakala bloğu içerdiği bir proje gördüm (yani tüm işlevin içindeki kod, deneme-yakalama bloğu ile çevrilidir). Bu iyi bir uygulama mı?
  6. Try-catch ve __try __except arasındaki fark nedir?


"Ne zaman bir istisna yapılmalı" dan daha spesifik sorular sormanız gerekecek. Olağanüstü bir şey olduğunda bir istisna atarsınız.
Falmarri

Bunu PHP ile ilgili yazdım, ancak hemen hemen her şeyin C ++ için geçerli olduğunu düşünüyorum. Blog gönderisine göz atın .
ircmaxell

Yanıtlar:


96

Okumalısınız olduğunu düşündüğüm istisnalar hakkında oldukça kapsamlı bir rehber:

İstisnalar ve hata işleme - C ++ SSS veya C ++ SSS lite

Genel bir kural olarak, programınız harici biryürütmeyi engelleyen sorun. Sunucudan veri alırsanız ve bu veriler geçersizse, bir istisna atın. Disk alanı dolu? Bir istisna atın. Kozmik ışınlar veri tabanını sorgulamanızı engeller mi? Bir istisna atın. Ancak kendi programınızın içinden bazı geçersiz veriler alırsanız - bir istisna atmayın. Sorununuz kendi kötü kodunuzdan kaynaklanıyorsa, buna karşı korunmak için ASSERT kullanmak daha iyidir. Programın üstesinden gelemediği sorunları belirlemek ve bunları kullanıcı hakkında anlatmak için istisna işlemesi gereklidir, çünkü kullanıcı bunları halledebilir. Ancak programınızdaki hatalar kullanıcının başa çıkabileceği bir şey değildir, bu nedenle programın çökmesi "answer_to_life_and_universe_ve_herything 42 değildir! Bu asla olmamalı !!!! 11" istisnasından daha azını söyleyecektir.

Onunla yararlı bir şey yapabileceğiniz bir istisna yakalayın, örneğin bir mesaj kutusu görüntüleyin. Kullanıcı girdisini bir şekilde işleyen bir işlevin içinde bir istisna yakalamayı tercih ederim. Örneğin, kullanıcı "Tüm hunamları yok et" düğmesine basar ve annihilateAllHunamsClicked () işlevinin içinde "yapamam" demek için bir try ... catch bloğu vardır. Hunamkind'in yok edilmesi düzinelerce ve düzinelerce işlevi çağırmayı gerektiren karmaşık bir işlem olsa da, yalnızca bir try ... catch vardır, çünkü bu bir kullanıcı için atomik bir işlemdir - tek bir tıklama. Her işlevdeki istisna kontrolleri gereksiz ve çirkin.

Ayrıca, RAII'ye yeterince aşina olmayı öneremem - yani, başlatılan tüm verilerin otomatik olarak yok edilmesini sağlamak için. Ve bu, yığın üzerinde olabildiğince çok başlatma yaparak elde edilebilir ve yığın üzerinde bir şeyi başlatmanız gerektiğinde, bir tür akıllı işaretçi kullanın. Yığın üzerinde başlatılan her şey, bir istisna atıldığında otomatik olarak yok edilecektir. C tarzı aptal işaretçiler kullanırsanız, bir istisna atıldığında bellek sızıntısı riskiyle karşı karşıya kalırsınız, çünkü istisnalar üzerine onları temizleyecek kimse yoktur (elbette, sınıfınızın üyeleri olarak C tarzı işaretçileri kullanabilirsiniz, ancak yıkıcıda halledilir).


Değerli katkılarınız için teşekkürler. > "Programın ele alamadığı sorunları tanımlamak ve kullanıcı hakkında bilgi vermek için istisna işleme gerekir, çünkü kullanıcı bunları> halledebilir" Bir istisna atmak yerine hata değerini döndürebilir ve çağıran işlevde hatayı kontrol edebilirim ve kullanıcının üstesinden gelmesine yardımcı olacak bir mesaj görüntüler.
Umesha MS

Özellikle bu bölümdeki üçüncü ve dördüncü kod parçacıklarına tekrar bakın: parashift.com/c++-faq-lite/exceptions.html#faq-17.2 İstisnalar harikadır çünkü hatalarınızın her derinlikten yüzeye çıkmasına izin verirler Çağrı yığını gibi ... Hata kodları
batisferler

2
@Septagram "Eğer sorununuz kendi kötü kodunuzdan kaynaklanıyorsa, buna karşı korunmak için ASSERT kullanmak daha iyidir.": Bir iddia, buggy dalına bağlı olmayan görevlere devam etmenize izin vermez (sadece programınız bir işlevdeki bir hata, başka yararlı şeyler yapamayacağı anlamına gelmez). Özel kaydediciler kullanmanıza izin vermez. RAII kullanarak yararlandığınız yıkıcıları atlayacaktır (program sona ermeden önce dosya arabelleklerinizin temizlenmesini ister misiniz? O fclosezaman bu yıkıcıları atlamayın !). Size tam bir yığın izi vermez.
daemonspring

RAII ve "aptal işaretçiler" hakkında söylenecek bir şey. Sırf "aptal bir işaretçi" kullanmanız RAII'yi takip etmediğiniz anlamına gelmez. Yalnızca sistem kaynaklarını ayırdığınızda ayrıldıklarından emin olmanız gerektiğini unutmayın. İşaretçi, yığın üzerinde bir bellek adresini tutan basit bir değişkendir. "Aptal bir işaretçi" kullanmak için nesne ayırma ve başlatma gerekli değildir. "Aptal bir işaretçi", başka bir yere tahsis edilmiş bir nesnenin adresini basitçe tutabilir ve kullanımı mükemmeldir. (sonraki yoruma devam)
SeanRamey

Ekrana bir şeyler çizmek için Görüntüleme nesnesinin adresini bir işaretçide depolayan bir Renderer nesneniz olabilir, ancak bir akıllı işaretçi kullanamazsınız çünkü Renderer nesnesini yok ettiğinizde akıllı bir işaretçi Görüntüleme nesnesini yok eder. , ki olmasını istemezsin. Bu durumda, ya "aptal işaretçi" ya da referans, gitmenin tek yoludur.
SeanRamey

12

İstisnalar, çeşitli durumlarda yararlıdır.

Birincisi, ön koşulu hesaplama maliyetinin çok yüksek olduğu bazı işlevler vardır, ön koşulun karşılanmadığı tespit edilirse, sadece hesaplamayı yapmak ve bir istisna dışında iptal etmek daha iyidir. Örneğin, tekil bir matrisi tersine çeviremezsiniz, ancak tekil olup olmadığını hesaplamak için çok pahalı olan determinantı hesaplarsınız: her halükarda işlev içinde yapılması gerekebilir, bu nedenle matrisi tersine çevirmeyi deneyin ve rapor edin bir istisna atarak yapamazsanız bir hata. Bu, olumsuz ön koşul kullanımı olarak temelde bir istisnadır .

Ayrıca, kodunuzun zaten karmaşık olduğu ve hata bilgilerini çağrı zincirinden geçirmenin zor olduğu başka durumlar da vardır. Bunun nedeni kısmen C ve C ++ 'nın bozuk veri yapısı modellerine sahip olmasıdır: başka, daha iyi yollar da vardır, ancak C ++ bunları desteklemez (Haskell'de monad kullanmak gibi). Bu kullanım temelde bunu doğru yapmaktan rahatsız olamam, bu yüzden bir istisna atacağım : doğru yol değil ama pratik.

Daha sonra istisnaların ana kullanımı vardır: bellek veya disk alanı gibi yeterli kaynaklar gibi harici ön koşullar veya değişmezler mevcut olmadığında rapor etmek. Bu durumda genellikle programı veya büyük bir alt bölümünü sonlandırırsınız ve istisna, sorunla ilgili bilgi aktarmanın iyi bir yoludur. C ++ İstisnaları, programın devam etmesini engelleyen hataları bildirmek için tasarlanmıştır .

C ++ dahil çoğu modern dilde kullanılan istisna işleme modelinin bozuk olduğu bilinmektedir . Çok fazla güçlü. Teorisyenler artık tamamen açık olan "bir şey fırlat" ve "belki ve belki yakala" modelinden daha iyi modeller geliştirdiler. Ayrıca, istisnaları sınıflandırmak için tür bilgisini kullanmak çok da iyi bir fikir değildi.

Yapabileceğiniz en iyi şey Yani orada gerçek bir hatadır ve ne zaman idareli, atış istisnalar başa başka bir yol olduğunda ve fırlatma noktasına mümkün olduğunca yakın istisnaları ölçülü bir şekilde atmaktır .


15
"İstisna işlemenin bozuk olduğu biliniyor" ve "Teorikçiler artık daha iyi modeller geliştirdiler" için bazı bağlantılar / referanslar ekleyebilir misiniz lütfen?
Juraj Blaho

1
İstisnaları yakalarken çoğu kez bilinmesi gereken, ancak çoğu istisnanın yararlı veri sağlamadığı kritik bir şey, istisnayı atan kodun sistemin durumu üzerinde herhangi bir etkisinin olup olmadığıdır. Teorisyenlerin modellerinden herhangi biri bununla ilgileniyor mu?
supercat

@JurajBlaho Bahsettiğiniz bağlantıları / referansları başarılı olmadan bulmaya çalıştım. Sonuna eklemek için cevabını düzenleyebilir misiniz?
ForceMagic

Örnek 1 ve 3'e katılıyorum. Bununla birlikte, eğer kod çok karmaşıksa, bir istisna atma düşünceniz, belki biraz yeniden düzenlemeye ihtiyacınız olacağını düşünüyorum. Assert ayrıca, kodun düzgün çalışıp çalışmadığını kontrol etmenin iyi bir yoludur (daha da iyi) ve aslında istisnadan daha ucuzdur. Bu konuyla ilgilenen herkese Pragmatik Programcı adlı kitaptan 2 bölüm (Girişken Programlama ve İstisnalar Ne Zaman Kullanılmalı) öneririm.
ForceMagic

1
Bağlantılara gerek yok. Beyin kullanın. Yakalanmayan bir istisna atabilirsiniz. Bu kötü. Gitmekten daha kötü çünkü goto en azından her zaman bir yere gidiyor. Statik tipleme, istisna spesifikasyonlarıyla baş edemez: polimorfik fonksiyonların istisna spesifikasyonuna sahip olabileceği aklı başında bir sistem yoktur, çünkü bu, belirli bir tip değişkenine bağlıdır. Bunların yeni C ++ Standardından kaldırıldığına dikkat edin. Yeni modelin adı "sınırlandırılmış süreklilikler": en.wikipedia.org/wiki/Delimited_continuation
Yttrill

4

Sorununuz kendi kötü kodunuzdan kaynaklanıyorsa, buna karşı korunmak için ASSERT kullanmak daha iyidir. Programın üstesinden gelemediği sorunları belirlemek ve bunları kullanıcı hakkında anlatmak için istisna işleme gereklidir, çünkü kullanıcı bunları halledebilir. Ancak programınızdaki hatalar kullanıcının başa çıkabileceği bir şey değildir, bu nedenle programın çökmesi pek bir şey söylemez

Kabul edilen cevabın bu yönüne katılmıyorum . Bir iddia, bir istisna atmaktan daha iyi değildir. İstisnalar yalnızca çalışma zamanı hataları (veya "harici sorunlar") için uygunsa, ne işe yarar std::logic_error?

Mantık hatası, neredeyse tanımı gereği bir programın devam etmesini engelleyen koşul türüdür. Program mantıksal bir yapı ise ve bu mantığın etki alanı dışında bir koşul meydana gelirse, nasıl devam edebilir? Elinizden geldiğince girdiler toplayın ve bir istisna atın!

Önceki sanat yok gibi değil. std::vector, ancak birini adlandırmak gerekirse, bir mantık hatası istisnası atar std::out_of_range. Eğer standart kütüphane kullanma ve standart istisnaları yakalamak için üst düzey bir işleyici yoksa - çağırmak üzere yalnızca neyi () ve çıkış (3) - ardından programlar ani sessiz, fesih tabidir.

İddia makrosu çok daha zayıf bir korumadır. İyileşme yok. Diğer bir deyişle, bir hata ayıklama derlemesi çalıştırmıyorsanız, bu durumda yürütme olmaz . İddia makrosu, hesaplamanın bugünkünden 6 kat daha yavaş olduğu bir çağa aittir. Mantık hatalarını test etme zahmetine girecek, ancak önemli olduğunda bu testi kullanmayacaksanız, üretimde, kodunuza çok güvenmeniz iyi olur!

Standart kütüphane, mantık hatası istisnaları sağlar ve bunları kullanır. Bir sebepten dolayı oradalar: çünkü mantık hataları meydana gelir ve istisnaidir. Sırf C'nin iddiaları öne çıkarması, bir istisna işi çok daha iyi ele aldığında, böylesine ilkel (ve tartışmasız, yararsız) bir mekanizmaya güvenmek için bir neden değildir.


3

Bunun için en iyi okuma

İstisna yönetimi son on bir buçuk yılda çok konuşuldu. Bununla birlikte, istisnaların nasıl düzgün bir şekilde ele alınacağına dair genel bir fikir birliğine rağmen, kullanım konusunda bir bölünme var olmaya devam ediyor. Hatalı istisna işleme, tespit edilmesi ve önlenmesi kolaydır ve basit bir kod (ve geliştirici) kalite metriğidir. Mutlak kuralların yakın fikirli veya abartılı olduğunu biliyorum, ancak genel bir kural olarak, dene / yakala kullanmamalısın

http://codebetter.com/karlseguin/2010/01/25/don-t-use-try-catch/


3
Bu makale gerçekten " try/ kullanma" demeye çalışmıyor catch {}mu?
Craig McQueen

2

1. Sonuç olarak veya problemin ortasında bir yerde bir istisna olma olasılığı olduğunda koda bir istisna kontrolü eklenir.

2. Try-catch bloğunu yalnızca gerekli olduğu durumlarda kullanın. Her bir dene-yakala bloğunun kullanımı, kodun optimizasyonunu kesinlikle azaltan ekstra bir koşul kontrolüne eklenir.

3. _try_except'in geçerli bir değişken adı olduğunu düşünüyorum ....


3
Bilginize, __try ve __except, Microsoft'un Yapılandırılmış Özel Durum İşleme (SEH) içindir. msdn.microsoft.com/en-us/library/s58ftw19(v=vs.80).aspx
axw

0

Temel fark şudur:

  1. Biri sizin için hata işlemeyi yapar.
  2. biri kendininkini yapmaktır.

    • Örneğin, yapabileceğiniz bir ifadeniz var 0 divide error. Try catch kullanmak 1.hata oluştuğunda size yardımcı olacaktır. Veya bir ihtiyaç if a==0 then..içinde2.

    • Eğer istisnayı yakalamaya errorçalışmazsanız , daha hızlı olduğunu sanmıyorum, sadece basitçe baypas edin, eğer meydana gelirse threwbir dış işleyiciye olacaktır.

Kendinizi teslim etmek, sorunun daha ileri gitmemesi ve çoğu durumda hızda avantaj sağlamanız anlamına gelir, ancak her zaman değil.

Önerin: Sadece basit ve mantıklı bir durumda kendinizle ilgilenin.


-3

Çoğu C / C ++ sadeliği, istisnaları tamamen caydırır. Ana eleştiriler:

  1. Yavaş - Tabii ki gerçekten "yavaş" değil. Ancak, saf c / c ++ ile karşılaştırıldığında, oldukça fazla ek yük vardır.
  2. Hatalar sunar - İstisnaları doğru şekilde işlemezseniz, istisnayı atan işlevdeki temizleme kodunu gözden kaçırabilirsiniz.

Bunun yerine, bir işlevi her çağırdığınızda dönüş değerini / hata kodunu kontrol edin.


15
Saçmalık. İlk olarak, C ++ 'dan bahsediyoruz - "C / C ++" yoktur ve elbette yalnızca C programcıları istisnalardan rahatsız olur. "saf C / C ++" mevcut değildir ve istisnalar "saf C ++" nın bir parçasıdır - bunlar Standarttadır. Hatalı istisna işleme kodu yazabilir ve hatalı hata döndüren kod veya hatalı hata durumu kodu yazabilirsiniz - istisnaları genel olarak hataya daha yatkın olarak nitelendirmek yanıltıcıdır. Maalesef bu
SO'da

1
İsterseniz beni not edin, ancak C geçmişinden geliyorum, size söyleyebilirim ki, kendim ve diğer birçok kişi istisnaları kullanmaktan tamamen kaçınıyor.
uçak

4
1. Yalnızca bir istisna gerçekten atıldığında yavaştır. İstisnalara istisna denir, çünkü istisnai durumlarda ortaya çıkarlar. Saniyede 9000'den fazla istisna atan program yanlış yapıyor. 2. Tamamen yeni silme ile bellek yönetimi yapmamaya özen gösterirseniz, temizleme sizin için yapılacaktır. C tarzı bellek yönetimi, istisnalara göre çok daha fazla hataya açıktır. 3. Dönüş değerinin kontrol edilmesi fazladan çok sayıda kod satırı ekler, dolayısıyla daha az okunabilir ve daha az bakım yapılabilir hale getirir.
Septagram

3
1) derleyiciye bağlı olarak doğru olmayabilir. Ve tüm istisnalar, çalıştırılabilir boyutu artıran ve işleri yavaşlatan iyi miktarda bayt kodu ekler. 2) tamamen yeni silme her zaman kullanılır, her şey bir yığın nesnesi olamaz. 3) dönüş değerlerini kontrol etmek daha fazla kod satırı olabilir, ancak tartışmaya açık bir şekilde daha sürdürülebilirdir. Kabul etmeyebilirsiniz, ancak C ++ istisnalarının çoğu durumda kötü olduğu genel kabul gören makul bir inanıştır. Örnek olarak gömülü C ++ 'ya bir göz atın.
hız düzlemi

11 olumsuz oy ve 8 olumlu oy. Açıkça görülüyor ki, bu görüş genel fikir birliğini yansıtmasa da, açıkladığım nedenlerden ötürü istisnalara karşı savaşan büyük bir geliştirici grubu var.
2020
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.