C ++ 'da istisnaların deyimsel kullanımı


16

İsocpp.org kural dışı durum SSS durumu

Bir fonksiyonun kullanımındaki kodlama hatasını belirtmek için atmayı kullanmayın. Süreci bir hata ayıklayıcıya göndermek veya işlemi kilitlemek ve geliştiricinin hata ayıklaması için çökme dökümünü toplamak için onaylama veya başka bir mekanizma kullanın.

Diğer taraftan, standart kütüphane std :: logic_error ve tüm türevlerini tanımlar, ki bu bana diğer şeylerin yanı sıra, programlama hatalarını da ele almaları gerekiyor gibi görünüyor. Boş bir dize std :: stof'a (bir geçersiz_argument atacak) programlama hatası değil mi? '1' / '0' dan farklı karakterler içeren bir dizeyi std :: bitset'e (invalid_argument atar) bir programlama hatası değil mi? Std :: bitset :: çağrısı, bir programlama hatası değil, geçersiz bir indeksle ayarlanacak mı (out_of_range'u atacak)? Bunlar değilse, test edilecek bir programlama hatası nedir? Std :: bitset string tabanlı kurucu sadece C ++ 11'den beri var, bu nedenle istisnaların idiyomatik kullanımı düşünülerek tasarlanmış olmalıdır. Öte yandan insanlar bana logic_error temelde hiç kullanılmaması gerektiğini söyledim.

İstisnalarla sıkça karşılaşılan bir diğer kural da "istisnai durumlarda istisnaları kullan" dır. Ancak bir kütüphane fonksiyonunun hangi koşulların istisnai olduğunu nasıl bilebilir? Bazı programlar için, bir dosyayı açamamak olağanüstü olabilir. Diğerleri için, bellek ayıramayan istisna olmayabilir. Aralarında 100'lü vaka var. Soket oluşturamıyor musunuz? Bir sokete veya dosyaya bağlanılamıyor veya veri yazılamıyor musunuz? Giriş ayrıştırılamıyor mu? Olağanüstü olabilir, olmayabilir. Fonksiyonun kendisi genellikle bilemez, ne tür bir bağlam olarak adlandırıldığı hakkında hiçbir fikri yoktur.

Peki, belirli bir işlev için istisnalar kullanmam gerekip gerekmediğime nasıl karar vermeliyim? Bana öyle geliyor ki, gerçekten tutarlı olan tek yol onları her hata işleme veya hiçbir şey için kullanmaktır. Ve standart kütüphaneyi kullanıyorsam, bu seçim benim için yapıldı.


6
Bu SSS girişini çok dikkatli okumalısınız . Yalnızca kodlama hataları için geçerlidir , geçersiz veriler için değil, boş bir nesnenin kaydının silinmesi veya genel çalışma zamanı kötülüğü ile ilgili herhangi bir şey. Genel olarak, iddialar asla olmaması gereken şeyleri tanımlamakla ilgilidir . Diğer her şey için istisnalar, hata kodları vb. Vardır.
Robert Harvey

1
@RobertHarvey hala aynı soruna sahip - bir şey insan müdahalesi olmadan çözülebilir veya çözülemezse, sadece bir programın üst katmanları tarafından bilinir.
cooky451

1
Yasallığa kapılıyorsunuz. Artıları ve eksileri değerlendirin ve kendi kararınızı verin. Ayrıca, sorunuzun son paragrafı ... Ben bunu açıkça görmüyorum. Gerçeğiniz muhtemelen birkaç gri tonuna daha yakın olduğunda, düşünmeniz çok siyah ve beyazdır.
Robert Harvey

4
Bu soruyu sormadan önce herhangi bir araştırma yapmaya çalıştınız mı? C ++ hata işleme deyimleri neredeyse kesinlikle web üzerinde detaylandırma tartışılır. Bir SSS girişine bir referans, iyi bir araştırma yapmak değildir. Araştırmanızı yaptıktan sonra hala kendi kararınızı vermeniz gerekecek. Beni, programlama okullarımızın, kendileri için nasıl düşüneceklerini bilmeyen akılsız yazılım deseni kodlayan robotlar yarattığı konusunda başlama.
Robert Harvey

2
Bu teorime böyle bir kuralın gerçekten bulunmayabileceğine inanır. Sorunuza cevap verip veremeyeceklerini görmek için The C ++ Lounge'dan bazı kişileri davet ettim , ancak oraya her gittiğimde, tavsiyeleri "C ++ kullanmayı bırak, beyninizi kızartır." Bu yüzden tavsiyelerini kendi sorumluluğunuzda alın.
Robert Harvey

Yanıtlar:


15

İlk olarak, std::exceptionçocukların ve çocuklarının uzun zaman önce tasarlandığını belirtmek zorundayım . Bugün tasarlansaydı muhtemelen (neredeyse kesinlikle) farklı olacak birkaç parça var.

Beni yanlış anlamayın: tasarımın oldukça iyi çalışmış parçaları var ve C ++ için bir istisna hiyerarşisinin nasıl tasarlanacağına dair oldukça iyi örnekler var (örneğin, diğer sınıfların çoğunun aksine, ortak kök).

Özellikle baktığımızda logic_error, biraz muamma var. Bir yandan, konuyla ilgili makul bir seçiminiz varsa, alıntıladığınız tavsiye doğrudur: genellikle hata ayıklanıp düzeltilebilmesi için mümkün olduğunca hızlı ve gürültülü bir şekilde başarısız olmak en iyisidir.

Ancak daha iyisi ya da daha kötüsü, genel olarak yapmanız gerekenler etrafındaki standart kütüphaneyi tanımlamak zordur . Bunları abort()yanlış girdi verildiğinde programdan çıkmak (örneğin, aramak ) olarak tanımladıysa , bu durum için her zaman böyle olurdu - ve aslında bunun gerçekten doğru bir şey olmadığı birkaç koşul vardır. , en azından konuşlandırılmış kodda.

Bu, (en azından yumuşak) gerçek zamanlı gereksinimler ve yanlış çıktı için asgari ceza gerektiren kodlar için geçerlidir. Örneğin, bir sohbet programı düşünün. Bazı ses verilerinin kodunu çözüyorsa ve bazı yanlış girişler alıyorsa, kullanıcının çıkışta milisaniyelik bir statikle yaşaması tamamen kapanan bir programdan çok daha mutlu olacaktır. Benzer şekilde, video oynatımı yapılırken, giriş akışı bozulduğu için programın özet olarak çıkmasından bir veya iki kare için bazı pikseller için yanlış değerler üreterek yaşamak daha kabul edilebilir olabilir.

Belirli hata türlerini bildirmek için istisnalar kullanıp kullanmayacağınıza gelince: haklısınız - aynı işlem, nasıl kullanıldığına bağlı olarak bir istisna olarak nitelendirilebilir veya olmayabilir.

Öte yandan, aynı zamanda yanılıyorsunuz - standart kütüphaneyi kullanmak (bu mutlaka) sizi bu kararı zorlamaz. Bir dosyayı açma durumunda, normalde bir iostream kullanırsınız. Iostreams de tam olarak en son ve en büyük tasarım değildir, ancak bu durumda işleri doğru yaparlar: bir hata modu ayarlamanıza izin verir, böylece bir dosyayı açmanın bir istisna atılmasına neden olup olmadığını kontrol edebilirsiniz. Dolayısıyla, uygulamanız için gerçekten gerekli bir dosyanız varsa ve açamıyorsanız, bazı ciddi düzeltici eylemler yapmanız gerektiği anlamına gelir, o zaman dosyayı açamazsa bir istisna atmasını sağlayabilirsiniz. Açmaya çalışacağınız çoğu dosya için, yoksa veya erişilebilir değilse, sadece başarısız olurlar (bu varsayılan değerdir).

Nasıl karar verdiğinize gelince: Kolay bir cevap olduğunu sanmıyorum. Daha iyi ya da kötü için, "istisnai durumların" ölçülmesi her zaman kolay değildir. Kesinlikle karar verilmesi kolay vakalar olağandışı olmakla birlikte, sorgulanmaya açık olduğu veya eldeki fonksiyonun etki alanının dışında olan bağlam bilgisi gerektiren durumlar vardır (ve muhtemelen her zaman olacaktır). Bu gibi durumlarda, en azından iostreams'in bu kısmına kabaca benzer bir tasarım düşünmeye değer olabilir, burada kullanıcı başarısızlığın bir istisna ile sonuçlanıp sonuçlanmayacağına karar verebilir. Alternatif olarak, biri başarısızlığı belirtmek için istisnalar atacak, diğeri başka araçlar kullanan iki ayrı işlev grubuna (veya sınıflara vb.) Sahip olmak tamamen mümkündür. Bu rotaya giderseniz,


9

Std :: bitset string tabanlı kurucu sadece C ++ 11'den beri var, bu nedenle istisnaların idiyomatik kullanımı düşünülerek tasarlanmış olmalıdır. Öte yandan insanlar bana logic_error temelde hiç kullanılmaması gerektiğini söyledim.

Buna inanmayabilirsiniz, ancak farklı C ++ kodlayıcıları aynı fikirde değil. Bu yüzden SSS bir şey söylüyor ama standart kütüphane aynı fikirde değil.

SSS çökmeyi savunuyor çünkü hata ayıklamak daha kolay olacak. Çöküyor ve bir çekirdek dökümü alırsanız, başvurunuzun tam durumuna sahip olacaksınız. Bir istisna atarsanız, bu durumun çoğunu kaybedersiniz.

Standart kütüphane kodlayıcıya hatayı yakalama ve olası bir hata ile başa çıkabilme kabiliyetinin hata ayıklamadan daha önemli olduğu teorisini alır.

Olağanüstü olabilir, olmayabilir. Fonksiyonun kendisi genellikle bilemez, ne tür bir bağlam olarak adlandırıldığı hakkında hiçbir fikri yoktur.

Buradaki fikir, eğer fonksiyonunuz durumun istisnai olup olmadığını bilmiyorsa, bir istisna atmaması gerektiğidir. Başka bir mekanizma aracılığıyla bir hata durumu döndürmelidir. Programda, durumun istisnai olduğunu bildiği bir noktaya ulaştığında, istisnayı atması gerekir.

Ama bunun kendi sorunu var. Bir fonksiyondan bir hata durumu döndürülürse, onu kontrol etmeyi hatırlamayabilirsiniz ve hata sessizce geçecektir. Bu, bazı insanların her türlü hata durumu için istisna atma lehine istisna kural olan istisnaları terk etmesine yol açar.

Genel olarak, kilit nokta, farklı insanların ne zaman istisna atacağı konusunda farklı fikirlere sahip olmasıdır. Tek bir uyumlu fikir bulamazsınız. Bazı insanlar dogmatik olarak bunun ya da bunun istisnalarla başa çıkmanın doğru yolu olduğunu iddia edecek olsa da, teori üzerinde kararlaştırılan tek bir kişi yoktur.

İstisnalar atabilirsiniz:

  1. Asla
  2. Her yerde
  3. Yalnızca programcı hatalarında
  4. Asla programcı hatalarında
  5. Sadece rutin olmayan (istisnai) arızalar sırasında

ve internette sizinle aynı fikirde olan birini bul. Sizin için çalışan stili benimsemeniz gerekecek.


Sadece koşullar gerçekten istisnai olduğunda istisnaları kullanma önerisinin, istisnaların düşük performans gösterdiği diller hakkında eğitim veren insanlar tarafından yaygın bir şekilde teşvik edildiğini belirtmek gerekir. C ++ bu dillerden biri değil.
Jules

1
@Jules - şimdi (performans) iddianızı yedeklediğinizde kesinlikle kendi cevabını hak ediyor. C ++ istisna performansı ise kesinlikle bir sorun, daha az, belki daha başka yerlerde daha ama "C ++ [istisnalar zayıf performansa sahip] bu dillerden biri değil" belirten kesinlikle tartışmaya açıktır olabilir.
Martin Ba

1
@MartinBa - diyelim ki Java, C ++ istisna performansı büyüklük sırası daha hızlıdır. Deneyler, bir istisnayı 1 seviyeye çıkarma performansının, C ++ 'da bir dönüş değerini işlemekten yaklaşık 50 kat daha yavaş, Java'da 1000 kattan daha yavaş olduğunu göstermektedir. Bu durumda Java için yazılan tavsiyeler, C ++ 'a fazladan düşünülmeden uygulanmamalıdır, çünkü ikisi arasında performansta bir büyüklük farkı vardır. Belki de "düşük performans" yerine "son derece düşük performans" yazmalıydım.
Jules

1
@Jules - bu sayılar için teşekkürler. (herhangi bir kaynaklar?) Ben yapabilirsiniz Java (ve C #) ihtiyaç kesinlikle yığın izini yakalamak, çünkü onlara inanmaya görünüyor gerçekten pahalı olabilir gibi. Sanırım ilk tepkiniz biraz yanıltıcıdır, çünkü 50x'lik bir yavaşlama bile oldukça ağırdır, özellikle. C ++ gibi performans odaklı bir dilde.
Martin Ba

2

Diğer birçok iyi cevap yazıldı, sadece kısa bir nokta eklemek istiyorum.

Geleneksel yanıt, özellikle ISO C ++ SSS yazıldığında, "C ++ istisna" ile "C-stil dönüş kodu" nu karşılaştırır. Üçüncü bir seçenek olarak, "a structveya union, veya bugünlerde boost::variantveya (önerilen) std::expectedgibi bir tür bileşik değer döndürmek dikkate alınmaz.

C ++ 11'den önce "bir kompozit tür döndür" seçeneği genellikle çok zayıftı. Çünkü, hareket semantiği yoktu, bu yüzden bir yapının içine ve dışına bir şeyler kopyalamak potansiyel olarak çok pahalıydı. En iyi performansı elde etmek için bu noktada kodunuzu RVO'ya göre biçimlendirmek son derece önemliydi . İstisnalar, bir kompozit türü etkili bir şekilde geri döndürmenin kolay bir yoluydu, aksi takdirde oldukça zor olurdu.

IMO, C ++ 11'den sonra, bu seçenek Result<T, E>bugünlerde Rust'da kullanılan deyime benzeyen "ayrımcı bir birliği döndür" seçeneğinin C ++ kodunda daha sık tercih edilmeli. Bazen hataları belirtmek daha basit ve daha kolay bir stildir. İstisnalar dışında, daha önce atmayan fonksiyonların bir refraktörden sonra aniden atmaya başlayabileceği ve programcılar bu tür şeyleri her zaman bu kadar iyi belgelemeyen her zaman bu olasılık vardır. Hata, ayrımcı bir birleşmedeki dönüş değerinin bir parçası olarak belirtildiğinde, programlayıcının, C stili hata işlemenin olağan eleştirisi olan hata kodunu göz ardı etme şansını büyük ölçüde azaltır.

Genellikle Result<T, E>isteğe bağlı destek gibi çalışır. operator boolBir değer veya hata olup olmadığını kullanarak test edebilirsiniz . Ve sonra operator *değere erişmek için say veya başka bir "get" işlevini kullanın. Genellikle bu erişim hız için işaretlenmez. Ancak bir hata ayıklama derlemesinde erişim denetlenecek ve bir iddianın gerçekte bir hata değil bir değer olduğundan emin olmasını sağlayabilirsiniz. Bu şekilde, hataları düzgün bir şekilde kontrol etmeyen herkes, daha sinsi bir sorundan ziyade zor bir iddia alacaktır.

Ek bir avantaj, yakalanmadığı takdirde yığına sadece rastgele bir mesafe uçtuğu istisnalardan farklı olarak, bu stil ile, bir işlev daha önce olmadığı bir hatayı bildirmeye başladığında, kodu işlemek için değiştirilir. Bu, sorunları daha yüksek hale getirir - geleneksel "yakalanmamış istisna" sorunu, bir çalışma zamanı hatasından daha çok derleme zamanı hatası gibi olur.

Bu tarzın büyük bir hayranı oldum. Genellikle, bugünlerde bunu ya da istisnaları kullanıyorum. Ama istisnaları büyük problemlerle sınırlamaya çalışıyorum. Ayrıştırma hatası gibi bir şey expected<T>için, örneğin dönmeye çalışıyorum . Gibi şeyler std::stoive boost::lexical_castbazı görece küçük bir sorun olması durumunda bir C ++ istisna "dize sayıya dönüştürülemedi" Bugünlerde bana çok kötü tat gibi görünüyor.


1
std::expectedhala kabul edilmeyen bir teklif, değil mi?
Martin Ba

Haklısın, sanırım henüz kabul edilmedi. Ama etrafta yüzen birkaç açık kaynak uygulaması var ve sanırım birkaç kez kendi başıma yuvarladım. Sadece iki olası durum olduğundan değişken bir tip yapmaktan daha az karmaşıktır. Ana tasarım hususları, tam olarak hangi arayüzü istiyorsun ve Andrescu'nun hata nesnesinin aslında olması gereken <T> gibi olmasını exception_ptrmı istiyorsun yoksa sadece bir yapı türü veya bir şey mi kullanmak istiyorsun? bunun gibi.
Chris Beck

Andrei Alexandrescu'nun konuşması burada: channel9.msdn.com/Shows/Going+Deep/… Böyle bir sınıfın nasıl oluşturulacağını ve ne tür düşünceleriniz olabileceğini ayrıntılı olarak gösteriyor.
Chris Beck

Önerilen [[nodiscard]] attribute, bu hata işleme yaklaşımı için yararlı olacaktır, çünkü yanlışlıkla hata sonucunu göz ardı etmemenizi sağlar.
CodesInChaos

- evet AA'nın konuşmasını biliyordum. Tasarımı paketten çıkarmak için oldukça garip buldum ( except_ptr) dahili olarak bir istisna atmanız gerekiyordu. Şahsen böyle bir aracın infazlardan tamamen bağımsız olması gerektiğini düşünüyorum. Sadece bir açıklama.
Martin Ba

1

Bu tasarımın bir parçası olduğu için oldukça öznel bir konudur. Tasarım temelde sanat olduğundan, tartışmak yerine bunları tartışmayı tercih ediyorum (tartıştığınızı söylemiyorum).

Benim için, istisnai durumlar iki çeşittir: kaynaklarla ve kritik operasyonlarla ilgilenenler. Kritik olarak kabul edilebilecek şey, eldeki probleme ve birçok durumda programcının bakış açısına bağlıdır.

Kaynak elde edilememesi, istisnalar atmada en iyi adaydır. Kaynak, bellek, dosya, ağ bağlantısı veya sorun ve platformunuza dayalı başka bir şey olabilir. Şimdi, bir kaynağı serbest bırakmamak bir istisna gerektiriyor mu? Bu yine değişiyor. Bellek bırakmanın başarısız olduğu hiçbir şey yapmadım, bu yüzden bu senaryodan emin değilim. Ancak, dosyaları kaynak sürümünün bir parçası olarak silmek başarısız olabilir ve benim için başarısız oldu ve bu hata genellikle çok işlemli bir uygulamada açık tutulan diğer işlemlerle bağlantılıdır. Sanırım diğer kaynaklar bir dosya gibi serbest bırakma sırasında başarısız olabilir ve genellikle bu sorunu getiren tasarım kusuru, bu yüzden düzeltmek istisna atmaktan daha iyi olurdu.

Sonra kaynakları güncelleme geliyor. Bu nokta, en azından benim için uygulamanın kritik operasyonları yönüyle yakından ilgilidir. Verileri virgülle ayrılmış dizeye göre değiştiren Employeebir işleve UpdateDetails(std::string&)sahip bir sınıf düşünün . Bellek yetersizliğine benzer şekilde, üye değişken değerlerinin atanmasının, bu tür alanlarda bu tür alanlarda deneyim eksikliğimden dolayı başarısız olduğunu hayal etmekte zorlanıyorum. Ancak, UpdateDetailsAndUpdateFile(std::string&)adından da anlaşılacağı gibi bir işlevin başarısız olması beklenir. Buna kritik operasyon diyorum.

Şimdi, sözde kritik operasyonun atılacak bir istisna gerektirip gerektirmediğini görmelisiniz. Yani, güncelleme, yıkıcıda olduğu gibi, sonunda mı oluyor, yoksa her güncellemeden sonra sadece paranoyak bir çağrı mı? Yazılmamış nesneleri düzenli olarak yazan bir geri dönüş mekanizması var mı? Diyorum ki, operasyonun kritikliğini değerlendirmek zorundasınız.

Açıkçası, kaynağa bağlı olmayan birçok kritik işlem var. Eğer UpdateDetails()yanlış veri verilir, bu ayrıntılarını güncellemek olmayacak ve burada bir istisna diye yetmezliği, bilinen yapılmalıdır. Ama bir fonksiyon düşünün GiveRaise(). Şimdi, eğer söz konusu çalışan sivri saçlı bir patronu olduğu için şanslıysa ve bir artış elde edemezse (programlama açısından, bazı değişkenlerin değeri bunun olmasını engeller), işlev aslında başarısız olmuştur. Burada bir istisna atar mısın? Diyorum ki, bir istisnanın gerekliliğini değerlendirmek zorundasınız.

Benim için tutarlılık, tasarım yaklaşımım açısından sınıflarımın kullanılabilirliğinden daha fazla. Demek istediğim, 'tüm Get işlevlerinin bunu yapması ve tüm Güncelleme işlevlerinin buna uyması' açısından düşünmüyorum, ancak belirli bir işlevin yaklaşımımdaki belirli bir fikre hitap edip etmediğini görüyorum. Yüzeyinde, sınıflar bir tür 'gelişigüzel' görünebilir, ancak kullanıcılar (çoğunlukla diğer takımlardan meslektaşlar) ne zaman rant veya sorduğunda, açıklayacağım ve memnun görünüyorlar.

Temelde dönüş değerlerini istisnalar ile değiştiren birçok kişi görüyorum çünkü C değil C ++ kullanıyorlar ve 'hata işleme' gibi güzel bir ayrım yapıyorlar vb. Ve 'dilleri karıştırmayı' durdurmamı tavsiye ediyorum. böyle insanlar.


1

Birincisi, diğerlerinin de belirttiği gibi, C ++ ve IMHO'da işler o kadar net değildir , çünkü C ++ 'da gereksinimler ve kısıtlamalar diğer dillerden biraz daha çeşitlidir, özellikle. "Benzer" istisna sorunları olan C # ve Java.

Ben std :: stof örnekte açığa çıkaracağım:

boş bir dizeyi std :: stof'a geçirme (invalid_argument atar) programlama hatası değil

Temel sözleşme anladığım kadarıyla, bu işlevin bir float için 's argümanı dönüştürmek çalışır ve olmasıdır herhangi bunu yapmaması istisna tarafından bildirilir. Her iki olası istisna da logic_errorprogramcı hatası anlamında elde edilir, fakat değil, "girdi hiçbir zaman bir kayan noktaya dönüştürülemez" anlamındadır.

Burada, a logic_error(çalışma zamanı) girdisi göz önüne alındığında, onu dönüştürmeye çalışmak her zaman bir hata olduğunu belirtmek için a kullanıldığını söyleyebiliriz - ancak bunu belirlemek ve size (istisna yoluyla) söylemek fonksiyonun görevidir.

Yan Not: Bu görünümde, bir runtime_error olabilir bir işleve aynı girdi verilmiş, teorik olarak farklı koşular için başarılı olabilir, bir şey olarak görülebilir. (örneğin bir dosya işlemi, DB erişimi vb.)

Daha Yan Not: C ++ regex kütüphanesi seçti gelen 's hatasını türetmek runtime_erroro durumlar vardır rağmen verebilir burada aynı sınıflandırılabilir (geçersiz normal ifade deseni).

Bu, IMHO'nun, C ++ ' da gruplandırmanın logic_veya runtime_hatanın oldukça bulanık olduğunu ve genel durumda (*) gerçekten fazla yardımcı olmadığını gösterir - belirli hataları ele almanız gerekiyorsa, muhtemelen ikisinden daha düşük yakalamanız gerekir.

(*): Bu, tek bir kod parçasının tutarlı olmaması gerektiği anlamına gelmez, ancak atmanız runtime_ya logic_da bir custom_şeylerin gerçekten o kadar önemli olmadığını düşünüyorum.


Her ikisine de yorum yapmak stofve bitset:

Her iki işlev de dizeleri bağımsız değişken olarak alır ve her iki durumda da:

  • belirli bir dizenin geçerli olup olmadığını arayan için kontrol etmek önemsiz değildir (örneğin en kötü durumda işlev mantığını çoğaltmanız gerekir; bitset durumunda, boş dizenin geçerli olup olmadığı hemen anlaşılmaz, bu nedenle ctor karar versin)
  • Dizeyi "ayrıştırmak" işlevinin sorumluluğudur, bu nedenle dizeyi doğrulamak zorundadır, bu nedenle dizeyi eşit olarak "kullanmak" için bir hata bildirdiği mantıklıdır (ve her iki durumda da bu bir istisnadır) .

istisnalar dışında sıkça ortaya çıkan kural "istisnai durumlarda istisnaları kullanmak" tır. Ancak bir kütüphane fonksiyonunun hangi koşulların istisnai olduğunu nasıl bilebilir?

Bu ifadenin IMHO'sunun iki kökü vardır:

Performans : Eğer bir işlev kritik bir yolda çağrılırsa ve "istisnai" durum istisnai değilse , yani önemli miktarda geçiş bir istisna atmayı, ardından istisna-çözme-makineleri için her seferinde ödeme yapmak mantıklı değildir. ve çok yavaş olabilir .

Hata işlemenin Yerellik : bir işlev çağrılır ve istisna yakalandıktan hemen ve işlendiği takdirde hata işleme daha ayrıntılı olacak, sonra bir istisna atma küçük nokta vardır ilecatch bir ile daha if.

Misal:

float readOrDefault;
try {
  readOrDefault = stof(...);
} catch(std::exception&) {
  // discard execption, just use default value
  readOrDefault = 3.14f; // 3.14 is the default value if cannot be read
}

Gibi fonksiyonlar İşte burada TryParsevs Parsedevreye girer: Yerel kod zaman için bir versiyonu bekliyor çözümlü dize geçerli olabilmesi için, bir sürümü yerel kod aslında varsayar zaman beklenen ayrıştırma başarısız olacağını (yani olmayan istisnai).

Aslında, stofsadece (olarak tanımlanır) bir sarıcıdır strtof, bu yüzden istisnalar istemiyorsanız, bunu kullanın.


Peki, belirli bir işlev için istisnalar kullanmam gerekip gerekmediğime nasıl karar vermeliyim?

IMHO, iki vakanız var:

  • "Kütüphane" gibi işlev (farklı bağlamlarda sıklıkla yeniden kullanılır): Temel olarak karar veremezsiniz. Muhtemelen her iki sürümü de sağlayın, belki bir hata bildiren bir hata ve döndürülen hatayı bir istisnaya dönüştüren bir sarmalayıcı.

  • "Uygulama" işlevi (bir uygulama kodu bloğu için özel, bazı yeniden kullanılabilir, ancak uygulamalar hata işleme tarzı, vb tarafından kısıtlanmıştır): Burada, genellikle oldukça net kesim olmalıdır. İşlevleri çağıran kod yolları istisnaları akıllıca ve kullanışlı bir şekilde ele alıyorsa, (ancak aşağıya bakın) hataları bildirmek için istisnaları kullanın . Uygulama kodu bir hata döndürme stili için daha kolay okunur ve yazılırsa, bunu kullanın.

Tabii aralarında yerler olacak - sadece ihtiyaç duyulanları kullanın ve YAGNI'yı hatırlayın.


Son olarak, SSS ifadesine geri dönmem gerektiğini düşünüyorum,

Bir fonksiyonun kullanımındaki kodlama hatasını belirtmek için atmayı kullanmayın. Süreci bir hata ayıklayıcıya göndermek veya işlemi kilitlemek için assert veya başka bir mekanizma kullanın ...

Ben bir şey ciddi berbat olduğunu veya arama kodu açıkça ne yaptığını bilmiyordu açık göstergesi olan tüm hatalar için abone .

Ama ne zaman bu uygundur dolayısıyla kütüphane alanı vs uygulama etki yukarıya bakınız, çoğu zaman son derece uygulama özgü olduğunu.

Bu , arama ön koşullarının doğrulanıp onaylanmayacağı ve nasıl doğrulanacağı sorusuna düşüyor , ancak buna girmeyeceğim, zaten çok uzun cevap :-)

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.