Ek olarak veya hata olarak istisnalar?


10

Profesyonel bir C programcısı ve hobici Obj-C programcısıyım (OS X). Son zamanlarda çok zengin sözdizimi nedeniyle C ++ 'a genişleme eğilimindeyim.

Şimdiye kadar kodlama istisnalarla pek ilgilenmedim. Objective-C onlara sahiptir, ancak Apple'ın politikası oldukça katıdır:

Önemli Programlama veya sınır dışı koleksiyon erişimi, değiştirilemeyen nesneleri değiştirmeye çalışmak, geçersiz bir mesaj göndermek ve pencere sunucusuyla bağlantıyı kaybetmek gibi beklenmedik çalışma zamanı hataları için istisnalar kullanılmalıdır.

C ++, istisnaları daha sık kullanmayı tercih ediyor gibi görünüyor. Örneğin, bir dosya açılamıyorsa RAII'deki wikipedia örneği bir istisna atar. Objective-C return nilbir çıkış parametresi tarafından gönderilen bir hata ile olur . Özellikle std :: ofstream her iki şekilde de ayarlanabilir.

İşte programcılar üzerinde birkaç cevaplar kullanmayı ilan ya buldum istisnalar yerine hata kodları ya da hiç istisnaları kullanmayın . Birincisi daha yaygın görünüyor.

C ++ için nesnel bir çalışma yapan kimseyi bulamadım. Bana öyle geliyor ki, işaretçiler nadir olduğu için, istisnalardan kaçınmayı seçersem iç hata bayraklarıyla gitmem gerekir. Üstesinden gelmek çok zahmetli olacak mı, yoksa istisnalardan daha iyi çalışacak mı? Her iki vakanın karşılaştırılması en iyi cevap olacaktır.

Düzenleme: Tamamen alakalı olmasa da, muhtemelen ne nilolduğunu netleştirmeliyim . Teknik olarak aynı NULL, ancak bir şey, bir mesaj göndermek için sorun değil nil. Böylece şöyle bir şey yapabilirsiniz

NSError *err = nil;
id obj = [NSFileHandle fileHandleForReadingFromURL:myurl error:&err];

[obj retain];

ilk çağrı geri gelse bile nil. Ve *objObj-C'de asla yapmadığınız gibi , bir NULL işaretçi dereference riski yoktur.


Imho, buradaki hatalarla nasıl çalıştığınızı bir parça Objective C kodu göstermeniz daha iyi olurdu. Görünüşe göre, insanlar sizin sorduğunuzdan farklı bir şey hakkında konuşuyor.
Gangnus

Bir bakıma istisnaları kullanmak için gerekçe arıyorum. Nasıl uygulandıkları hakkında bir fikrim olduğu için, ne kadar pahalı olabileceklerini biliyorum. Ama sanırım onların kullanımı için yeterince iyi bir argüman elde edebilirsem, bu şekilde gideceğim.
Per Johansson

Görünüşe göre, C ++ için onları kullanmamak için haklı bir gerekçeye ihtiyacınız var . Buradaki reaksiyonlara göre.
Gangnus

2
Belki de, şimdiye kadar neden daha iyi olduklarını açıklayan hiç kimse yoktu (hata kodlarıyla karşılaştırıldığında hariç). İstisnai olmayan şeyler için istisnalar kullanma kavramını sevmiyorum, ancak gerçeklere dayanmaktan daha içgüdüsel.
Per Johansson

"Sevmiyorum ... istisnai olmayan şeyler için istisnalar kullanarak" - kabul etti.
Gangnus

Yanıtlar:


1

C ++, istisnaları daha sık kullanmayı tercih ediyor gibi görünüyor.

Bazı yönlerden aslında Objective-C'den daha azını öneriyorum çünkü C ++ standart kütüphanesi genellikle en yaygın durum tasarım formunda ( operator[]yani,) rasgele erişim dizisinin sınır dışı erişimi gibi programcı hatalarını atmayacaktı veya geçersiz bir yineleyiciden vazgeçmeye çalışıyor. Dil, bir diziye sınırların dışında erişmeye veya boş bir işaretçiyi veya bu türden herhangi bir şeyi silmeyi bırakmaz.

Programcı hatalarını büyük ölçüde istisna işleme denkleminden çıkarmak aslında diğer dillerin sıklıkla yanıt verdiği çok büyük bir hata kategorisini ortadan kaldırır throwing. C ++ assert, bu tür durumlarda muhtemelen dil, bu tür çalışma zamanı denetimlerinin maliyetini dayatmak istemediğinden (sürüm / üretim derlemelerinde derlenmez, yalnızca hata ayıklama derlemeleri) veya yalnızca aksaklık (genellikle çökme) eğilimindedir. programcı, bu tür kontrolleri kendisi yapan bir kod yazarak maliyetleri ödemek istemedikçe, bu tür programcı hatalarını tespit etmek için gerekli olacaktır.

Sutter, C ++ Kodlama Standartlarında bu gibi durumlarda istisnalardan kaçınmayı bile teşvik eder:

Bir programlama hatasını bildirmek için bir istisna kullanmanın birincil dezavantajı, hata ayıklayıcının ihlalin tespit edildiği satırda satırın durumu bozulmadan başlatılmasını istediğinizde yığın gevşemesinin gerçekten olmasını istememenizdir. Özetle: Olabileceğini bildiğiniz hatalar var (bkz. 69 - 75. Maddeler). Olmaması gereken her şey için ve eğer varsa programcının hatası var assert.

Bu kural zorunlu olarak taş değildir. Bazı kritik görevlerde, programcı hatalarının meydana geldiği yerlerde ve programcı hatalarının throwvarlığında geçersiz bir şeyi ertelemeye veya sınırların dışına erişmeye çalışmak gibi düzenli olarak kaydeden ambalajlayıcılar ve bir kodlama standardı kullanmak tercih edilebilir , çünkü yazılımın bir şansı varsa, bu durumlarda kurtarılamayacak kadar maliyetli olabilir. Ancak genel olarak, dilin daha yaygın kullanımı, programcı hatalarının önüne geçmemeyi tercih eder.

Dış İstisnalar

C ++ 'da en sık teşvik edilen istisnaları gördüğümde (örneğin, standart komiteye göre), program dışındaki bazı harici kaynaklarda beklenmedik bir sonuç olduğu gibi "harici istisnalar" içindir. Bir örnek bellek ayıramıyor. Bir diğeri, yazılımın çalışması için gerekli olan kritik bir dosyayı açamıyor. Başka bir sunucu gerekli bir sunucuya bağlanamıyor. Diğeri ise, ortak vaka yürütme yolu bu harici kesintinin olmaması durumunda başarılı olmasını bekleyen bir işlemi iptal etmek için bir iptal düğmesine basan bir kullanıcıdır. Bütün bunlar, anında yazılımın ve onu yazan programcıların kontrolü dışındadır. Operasyonun (kitabımda gerçekten bölünmez bir işlem olarak düşünülmesi gereken) başarılı olmasını engelleyen dış kaynaklardan beklenmedik sonuçlardır.

işlemler

Bir trybloğa "işlem" olarak bakmayı teşvik ediyorum çünkü işlemler bir bütün olarak başarılı olmalı ya da bir bütün olarak başarısız olmalıdır. Bir şey yapmaya çalışıyorsak ve yarıda başarısız olursa, program durumuna yapılan herhangi bir yan etkinin / mutasyonun genellikle işlemin hiç yapılmadığı gibi geçerli bir duruma geri döndürülmesi için geri alınması gerekir, tıpkı bir sorguyu yarıya kadar işleyemeyen bir RDBMS'nin veritabanının bütünlüğünden ödün vermemesi gibi. Program durumunu doğrudan söz konusu işlemde değiştirirseniz, bir hatayla karşılaştığınızda "değiştirmemeniz" gerekir (ve burada kapsam korumaları RAII ile yararlı olabilir).

Daha basit alternatif isimli mutasyona yok orijinal program durumunu; bir kopyasını değiştirebilir ve ardından başarılı olursa kopyayı orijinali ile değiştirebilirsiniz (takasın alamayacağından emin olun). Başarısız olursa, kopyayı atın. Bu, genel olarak hata işleme için istisnalar kullanmasanız bile geçerlidir. Bir hata ile karşılaşmadan önce program durumu mutasyonları meydana gelmişse, bir "işlemsel" zihniyet uygun kurtarmanın anahtarıdır. Ya bir bütün olarak başarılı olur ya da bütünüyle başarısız olur. Mutasyonlarını yarıda başaramaz.

Bu, programcıların düzgün bir şekilde hata veya istisna işlemeyi nasıl yapacağını sorduğunu görünce tuhaf bir şekilde en az tartışılan konulardan biridir, ancak birçoğunda program durumunu doğrudan değiştirmek isteyen herhangi bir yazılımda doğru bir şekilde elde etmek en zor olanıdır. operasyonları. Saflık ve değişmezlik, iş parçacığı güvenliğine yardımcı oldukları ölçüde istisna güvenliği sağlamaya yardımcı olabilir, çünkü oluşmayan bir mutasyon / dış yan etkinin geri alınması gerekmez.

Verim

İstisnaların kullanılıp kullanılmayacağına dair bir başka yol gösterici performanstır ve bazı takıntılı, kuruş kısma, karşı üretken bir şekilde kastetmiyorum. Birçok C ++ derleyicisi "Sıfır Maliyet İstisnası İşleme" denen şeyi uygular.

Hatasız yürütme için sıfır çalışma zamanı ek yükü sunar, bu da C dönüş değeri hata işlemenin bile üstesinden gelir. Bir değiş tokuş olarak, bir istisnanın yayılmasının büyük bir yükü vardır.

Bu konuda okuduğum şeye göre, genel durum yürütme yollarınızın, olağanüstü yollara (özellikle C-tarzı hata kodu işleme ve yayılmasına eşlik eden ek yük bile değil) ek yük gerektirmemesine neden olur. yani throwingartık her zamankinden daha pahalı).

"Pahalı" miktarını belirlemek biraz zordur, ancak yeni başlayanlar için muhtemelen bir milyon döngüyü sıkı bir döngüye atmak istemezsiniz. Bu tür tasarım, istisnaların her zaman solda ve sağda meydana gelmediğini varsayar.

Sigara Hatalar

Ve bu performans noktası beni hatalara götürüyor, bu da her türlü başka dile bakarsak şaşırtıcı derecede bulanık. Ancak, yukarıda belirtilen sıfır maliyetli EH tasarımı göz önüne alındığında, throwbir sette bulunmayan bir anahtara yanıt olarak neredeyse kesinlikle istemediğinizi söyleyebilirim . Çünkü bu sadece bir hata değildir (anahtarı arayan kişi seti inşa etmiş ve her zaman var olmayan anahtarları aramayı beklemiş olabilir), ama bu bağlamda çok pahalı olurdu.

Örneğin, bir küme kesişme işlevi iki küme arasında geçiş yapmak ve ortak anahtarları aramak isteyebilir. Bir anahtar bulamazsanız threw, yinelemelerin yarısında veya daha fazlasında istisnalarla karşılaşabilirsiniz:

Set<int> set_intersection(const Set<int>& a, const Set<int>& b)
{
     Set<int> intersection;
     for (int key: a)
     {
          try
          {
              b.find(key);
              intersection.insert(other_key);
          }
          catch (const KeyNotFoundException&)
          {
              // Do nothing.
          }
     }
     return intersection;
}

Yukarıdaki örnek kesinlikle saçma ve abartılı, ancak üretim kodunda, C ++ 'da istisnalar kullanan diğer dillerden gelen bazı insanlar böyle bir şey gördüm ve bunun istisnaların uygun bir kullanımı olmadığını makul olarak pratik bir ifade olarak görüyorum. C ++ 'da. Yukarıdaki başka bir ipucu, catchbloğun kesinlikle yapacak hiçbir şeyi olmadığını ve sadece bu tür istisnaları zorla görmezden gelmek için yazıldığını göreceksiniz ve bu genellikle istisnaların muhtemelen C ++ 'da çok uygun bir şekilde kullanılmadığına dair bir ipucu (garantör olmasa da).

Bu tür durumlar için, başarısızlığı gösteren bir tür dönüş değeri ( falsegeçersiz bir yineleyiciye dönmekten veya nullptrbağlamda anlamlı olan herhangi bir şey ) genellikle çok daha uygundur ve ayrıca hata olmayan bir türden daha pratik ve üretkendir. durumda genellikle analog catchbölgeye ulaşmak için bazı yığın çözme işlemi gerektirmez .

Sorular

İstisnalardan kaçınmayı seçersem iç hata bayraklarıyla gitmem gerekir. Üstesinden gelmek çok zahmetli olacak mı, yoksa istisnalardan daha iyi çalışacak mı? Her iki vakanın karşılaştırılması en iyi cevap olacaktır.

Bazı gömülü sistemlerde veya kullanımlarını yasaklayan belirli bir durumda çalışmadığınız sürece, C ++ 'da istisnalardan kaçınmak benim için son derece üretken görünmektedir (bu durumda, hepsinden kaçınmak için yolunuzdan çıkmanız gerekir) Kütüphane ve dil işlevselliği, aksi takdirde throwkesinlikle kullanmak gibi nothrow new).

Herhangi bir nedenle istisnalardan kaçınmanız gerekiyorsa (örn: C API'sını dışa aktardığınız bir modülün C API sınırları boyunca çalışmak), birçok kişi benimle aynı fikirde olmayabilir, ancak aslında OpenGL gibi genel bir hata işleyicisi / durumu kullanmanızı öneririm glGetError(). Her iş parçacığı için benzersiz bir hata durumuna sahip olmak için iş parçacığı yerel depolamasını kullanabilirsiniz.

Bunun mantığı benim üretim ortamlarındaki ekipleri görmeye alışkın olmamam, ne yazık ki, hata kodları döndürüldüğünde tüm olası hataları iyice kontrol etmem. Kapsamlı olsaydı, bazı C API'leri hemen hemen her C API çağrısında bir hatayla karşılaşabilir ve kapsamlı kontrol aşağıdaki gibi bir şey gerektirir:

if ((err = ApiCall(...)) != success)
{
     // Handle error
}

... bu tür kontroller gerektiren API'yı çağıran neredeyse her kod satırı ile. Yine de bu kadar kapsamlı ekiplerle çalışma şansım olmadı. Genellikle bu tür hataları çoğu zaman yarısı, hatta çoğu zaman göz ardı ederler. İstisnaların bana en büyük cazibesi bu. Bu API'yı kaydırır ve throwbir hatayla eşit olarak eşit yaparsak , istisna muhtemelen göz ardı edilemez ve benim görüşüme ve deneyime göre, istisnaların üstünlüğü burada yatmaktadır.

Ancak istisnalar kullanılamıyorsa, global, iş parçacığı başına hata durumu en azından, hata kodlarını bana döndürmeyle karşılaştırıldığında büyük bir avantaj (eski bir hatayı daha sonradan biraz daha geç yakalama şansına sahip olabilir) tamamen eksik ve bize ne olduğunu tamamen kayıtsız bırakmak yerine bazı özensiz kod temeli oluştu. Hata birkaç satır önce veya önceki bir işlev çağrısında meydana gelmiş olabilir, ancak yazılım henüz çökmediyse, geriye doğru çalışmaya başlayabilir ve nerede ve neden oluştuğunu anlayabiliriz.

Bana öyle geliyor ki, işaretçiler nadir olduğu için, istisnalardan kaçınmayı seçersem iç hata bayraklarıyla gitmem gerekir.

Mutlaka işaretçilerin nadir olduğunu söylemem. Artık C ++ 11 ve sonrasında, kapların temel veri işaretleyicilerine ve yeni bir nullptranahtar kelimeye ulaşmak için yöntemler bile var . İstisnaların varlığında RAII uyumlu olmasının ne kadar kritik olduğu göz önüne alındığında, bunun yerine bir şeyi kullanabiliyorsanız, hafızanın sahibi olmak / yönetmek için ham işaretçiler kullanmanın genellikle akıllıca olmadığı düşünülür unique_ptr. Ancak hafızanın sahibi olmayan / yönetmeyen ham işaretçiler mutlaka (Sutter ve Stroustrup gibi insanlardan bile) çok kötü olarak kabul edilmez ve bazen bir şeye işaret etme yolu olarak (şeylere işaret eden endekslerle birlikte) çok pratiktir.

Bunlar, geçersiz kılındıktan sonra onlardan vazgeçmeye çalışıp çalışmadığınızı algılamayacak olan standart konteyner yineleyicilerinden (en azından sürümde, kontrol edilen yineleyiciler yok) daha az güvenli değildir. C ++, özel kullanımınız her şeyi sarmak ve sahip olmayan ham işaretçileri bile gizlemek istemediği sürece, hala utanç verici bir şekilde biraz tehlikeli bir dildir. Kaynakların RAII'ye (genellikle çalışma zamanı maliyeti olmadan gelir) uygun olması istisnalarla neredeyse kritiktir, ancak bunun dışında bir geliştiricinin açıkça istemediği maliyetlerden kaçınmak için kullanmak için en güvenli dil olmaya çalışmak gerekmez. başka bir şeyle takas etmek. Önerilen kullanım, sizi sarkan işaretçiler ve geçersiz yineleyiciler gibi şeylerden korumaya çalışmamaktadır, aksi takdirde (aksi takdirde kullanmaya teşvik ediliriz)shared_ptrStroustrup'un şiddetle karşı çıktığı her yerde). Bir şey olduğunda bir kaynağı düzgün bir şekilde serbest bırakmama / serbest bırakma / yok etme / kilidini açma / temizleme konusunda sizi korumaya çalışıyor throws.


14

İşte bir şey: C ++ 'ın benzersiz geçmişi ve esnekliği nedeniyle, istediğiniz herhangi bir özellik hakkında neredeyse herhangi bir görüş bildiren birini bulabilirsiniz. Bununla birlikte, genel olarak, yaptığınız şey C'ye ne kadar çok benziyorsa, o kadar kötü bir fikirdir.

İstisnalar söz konusu olduğunda C ++ 'ın çok daha gevşek olmasının nedenlerinden biri, tam olarak return nilistediğiniz zaman tam olarak yapamamanızdır. nilVakaların ve türlerin büyük çoğunluğunda olduğu gibi bir şey yoktur .

Ama işte basit gerçek. İstisnalar işlerini otomatik olarak yapar. Bir istisna attığınızda, RAII devreye girer ve her şey derleyici tarafından ele alınır. Eğer hata kodları kullandığınızda, sen onları kontrol etmek hatırlamak zorunda. Bu, doğası gereği istisnaları hata kodlarından önemli ölçüde daha güvenli hale getirir - kendilerini olduğu gibi kontrol ederler. Ayrıca, daha etkileyici. Bir istisna atın ve hatanın ne olduğunu söyleyen bir dize çıkarabilir ve hatta "Z yerine Y değerine sahip X hatalı parametre X" gibi belirli bilgiler de içerebilir. 0xDEADBEEF hata kodunu alın ve tam olarak neyi yanlış yaptınız? Emin dokümantasyon yukarı güncel eksiksiz ve umut ve "Kötü parametresini" olsun bile, size diyecektim asla hangiparametresi, sahip olduğu değer ve sahip olması gereken değerdi. Referans olarak yakalarsanız, polimorfik olabilirler. Son olarak, hata kodlarının asla yapamayacağı yerlerde, kurucular gibi istisnalar atılabilir. Peki genel algoritmalara ne dersiniz? std::for_eachHata kodunuzu nasıl kullanacaksınız? Uzman ipucu: Öyle değil.

İstisnalar her açıdan hata kodlarından büyük ölçüde üstündür. Asıl soru, iddialara karşı istisnalardır.

İşte bir şey. Kimse önceden programınızın hangi ön koşullarının çalıştığını, hangi arıza koşullarının olağandışı, hangilerinin önceden kontrol edileceğini ve hangilerinin hata olduğunu önceden bilemez. Bu genellikle, belirli bir hatanın program mantığını bilmeden bir iddia mı yoksa istisna mı olduğuna önceden karar veremeyeceğiniz anlamına gelir. Ayrıca, alt işlemlerinden biri başarısız olduğunda da devam edebilen bir işlem kural değil istisnadır .

Bence istisnalar var. Mutlaka hemen değil, sonunda. Bir istisna, programın bir noktadan kurtarabilmesini beklediğiniz bir sorundur. Ancak söz konusu operasyon, istisna gerektiren bir problemden asla kurtulamaz.

Onaylama hataları her zaman ölümcül, kurtarılamaz hatalardır. Bellek bozulması, bu tür şeyler.

Bir dosyayı açamadığınızda, bir iddia veya istisna mı? Eh, bir jenerik kütüphanede, daha sonra hata senaryoları bol olabilir ben istisna söyleyebilirim bu yüzden bir yapılandırma dosyası yüklenirken, örneğin, ele alınması, sadece, bunun yerine bir önceden oluşturulmuş varsayılan kullanabilir.

Bir dipnot olarak, etrafta dolaşan bazı "Boş Nesne Paterni" olayından bahsetmek istiyorum. Bu model korkunç . On yıl içinde bir sonraki Singleton olacak. Uygun bir null nesne üretebileceğiniz vaka sayısı miniktir .


Alternatif mutlaka basit bir int değildir. Obj-C'den alışkın olduğum NSError'a benzer bir şey kullanmam daha olası olurdu.
Per Johansson

C'yi değil, C Hedefini karşılaştırıyor. Bu büyük bir fark. Ve hata kodları satırları açıklıyor. Söylediğiniz doğru, sadece bu soruya bir şekilde cevap vermeyin. Hiçbir suçun anlamı yoktu.
Gangnus

Objective-C kullanan herkes elbette size kesinlikle, tamamen yanlış olduğunuzu söyleyecektir.
gnasher729

5

İstisnalar bir nedenle icat edildi, bu da tüm kodunuzun böyle görünmesini önlemek için:

bool success = function1(&result1, &err);
if (!success) {
    error_handler(err);
    return;
}

success = function2(&result2, &err);
if (!success) {
    error_handler(err);
    return;
}

Bunun yerine, bir istisna işleyicisi yukarı mainveya başka bir şekilde elverişli bir konumda bulunan aşağıdakine daha çok benzeyen bir şey alırsınız :

result1 = function1();
result2 = function2();

Bazı insanlar istisnasız bir yaklaşım için performans faydaları iddia ediyorlar, ancak bence okunabilirlik endişeleri, özellikle de if (!success)her yere serpiştirmek zorunda olduğunuz tüm kazan plakası için yürütme süresini eklediğinizde veya yoksa t içerir ve istisnaların gerçekleşme olasılığını göz önüne almak nispeten nadirdir.

Apple'ın neden istisnaların kullanılmasından vazgeçtiğini bilmiyorum. İşlenmeyen özel durumları yaymaktan kaçınmaya çalışıyorlarsa, gerçekten başardığınız tek şey, istisnaları belirtmek için boş işaretçiler kullanan kişilerdir;


1
İstisnasız kod aslında böyle görünüyorsa, ancak daha mantıklı olur, ancak genellikle böyle olmaz. Bu örüntü, error_handler hiçbir zaman geri dönmez, ancak nadiren de olsa ortaya çıkar.
Per Johansson

1

Referansta bulunduğunuz gönderide (hata kodlarına karşı istisnalar), bence farklı bir tartışma var. Soru, muhtemelen ERR001_FILE_NOT_WRITEABLE (veya eğer şanssızsanız kısaltılmış) gibi adlarla tamamlanan #define hata kodlarının genel bir listesine sahip olup olmadığınız gibi görünüyor. Ve, bu iş parçacığındaki ana nokta, bir polimorfik dilde nesne örnekleri kullanıyorsanız, böyle bir yordamsal yapının gerekli olmadığıdır. İstisnalar, türlerinden dolayı hangi hatanın meydana geldiğini ifade edebilir ve yazdırılacak mesaj (ve diğer şeyler) gibi bilgileri de kapsayabilir. Bu yüzden, bu konuşmayı, prosedürel olarak nesne yönelimli bir dilde programlayıp programlamayacağınızla ilgili olarak söylerim.

Ancak, kodda ortaya çıkan durumları ele almak için istisnalara ne zaman ve ne kadar güvenileceğinin konuşması farklıdır. İstisnalar atıldığında ve yakalandığında, geleneksel çağrı yığınından tamamen farklı bir kontrol akışı paradigması getiriyorsunuz. İstisna atma, temel olarak sizi çağrı yığınınızdan ayıran ve sizi belirsiz bir yere (müşteri kodunuzun istisnayı işlemeye karar verdiği her yerde) gönderen bir goto ifadesidir. Bu, istisna mantığını akla getirmeyi çok zorlaştırır .

Ve böylece, jheriko tarafından ifade edilen, bunların en aza indirilmesi gerektiği gibi bir duygu var. Yani, diyelim ki diskte mevcut olan veya olmayan bir dosyayı okuyorsunuz. Jheriko ve Apple ve yaptıkları gibi düşünenler (kendim dahil), bir istisna atmanın uygun olmadığını savunurlar - bu dosyanın yokluğu istisnai değildir , beklenir. İstisnalar normal kontrol akışının yerine geçmemelidir. ReadFile () yönteminizin bir boolean döndürmesini ve istemci kodunun dosyanın bulunamadığını false değerinden görmesini sağlamak da kolaydır. İstemci kodu daha sonra kullanıcı dosyasının bulunamadığını söyleyebilir veya sessizce bu durumu veya ne yapmak isterse halledebilir.

İstisna attığınızda, müşterilerinize yük getirmeye zorlarsınız. Onlara bazen, normal çağrı yığınından onları ayıracak ve uygulamalarının çökmesini önlemek için ek kod yazmaya zorlayacak kodlar veriyorsunuz. Böyle güçlü ve sarsıcı bir yük, yalnızca çalışma zamanında veya "erken başarısız" felsefesinin çıkarları için kesinlikle gerekliyse onlara zorlanmalıdır. Dolayısıyla, önceki durumda, uygulamanızın amacı bazı ağ işlemlerini izlemekse ve birileri ağ kablosunu çıkarırsa (felaketli bir hata sinyali veriyorsanız) istisnalar atabilirsiniz. İkinci durumda, yönteminiz null olmayan bir parametre bekliyorsa ve null verilirse bir istisna atabilirsiniz (uygun olmayan bir şekilde kullanıldığınıza işaret ediyorsunuz).

Nesneye yönelik dünyada istisnalar yerine ne yapılacağı konusunda, prosedürel hata kodu yapısının ötesinde seçenekleriniz vardır. Hemen akla gelen bir tanesi, OperationResult veya benzeri bir şey oluşturabilmenizdir. Bir yöntem bir OperationResult döndürebilir ve bu nesne işlemin başarılı olup olmadığı ve sahip olmasını istediğiniz diğer bilgiler hakkında bilgi sahibi olabilir (örneğin, bir durum mesajı, ancak daha açık bir şekilde, hata kurtarma stratejilerini kapsayabilir) ). İstisna atmak yerine bunu döndürmek, polimorfizme izin verir, kontrol akışını korur ve hata ayıklamayı çok daha basit hale getirir.


Sana katılıyorum, ama bana soruyu sormamın en nedeni bu değil.
Per Johansson

0

Temiz Kod'da , bu konudan bahseden güzel bir çift bölüm var - Apple bakış açısı eksi.

Temel fikir, işlevlerinizden asla sıfır döndürmemenizdir, çünkü:

  • Çok sayıda çoğaltılmış kod ekler
  • Kodunuzu karıştırıyor - Yani: Okumak zorlaşıyor
  • Çoğunlukla sıfır işaretçisi hatalarına neden olabilir veya belirli "din" programınıza bağlı olarak erişim ihlallerine neden olabilir

Eşlik eden diğer fikir, istisnaları kullanmanızdır, çünkü kodunuzdaki dağınıklığı daha da azaltmaya yardımcı olur ve sonunda izlenmesi ve bakımı zorlaşan (özellikle birden çok modül ve platformda) bir dizi hata kodu oluşturmak yerine müşterilerinizin deşifre etmeleri için bir acıdır, bunun yerine sorunun kesin doğasını tanımlayan, hata ayıklamayı basitleştiren ve hata işleme kodunuzu temel bir try..catchifade kadar basit bir şeye indirgeyecek anlamlı mesajlar oluşturursunuz .

COM geliştirme günlerimde, her hatanın bir istisna yarattığı ve her istisnanın Windows standart COM istisnalarını genişletmeye dayanan benzersiz bir hata kodu kimliği kullanması gereken bir projem vardı. Daha önce hata kodlarının kullanıldığı daha önceki bir projeden bir itirazıydı, ancak şirket tüm nesneleri yöneltmek ve işleri çok fazla yapma şeklini değiştirmeden COM-bandwagonuna atlamak istedi. Hata kodu numaralarının tükenmesi 4 ay sürdü ve bunun yerine istisnaları kullanmak için büyük kod parçalarını yeniden gözden geçirmek için bana düştü. Çabalarınızı önceden kurtarmak ve istisnaları akıllıca kullanmak daha iyidir.


Teşekkürler, ama NULL döndürmeyi düşünmüyorum. Zaten inşaatçılar karşısında mümkün görünmüyor. Bahsettiğim gibi, muhtemelen nesnede bir hata bayrağı kullanmak zorunda kalacağım.
Per Johansson
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.