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_error
programcı 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_error
o 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 stof
ve 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 TryParse
vs Parse
devreye 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, stof
sadece (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 :-)