Kişi std :: exception türetmeli / miras almalı?


15

İlk 'ciddi' C ++ kütüphanemi tasarlarken kendime şunu soruyorum:

İstisnalardan türetmek iyi bir stil std::exceptionmi ve yavruları mı ?!

Okuduktan sonra bile

Hala emin değilim. Çünkü, yaygın (ama belki de iyi değil) uygulamaların yanı sıra, bir kütüphane kullanıcısı olarak, bir kütüphane fonksiyonunun std::exceptionsadece kütüphane uygulamasında standart kütüphane fonksiyonları başarısız olduğunda ve bu konuda hiçbir şey yapamadığını varsayarım . Ama yine de, uygulama kodu yazarken, benim için çok uygun ve aynı zamanda sadece bir atmak isteyen IMHO iyi std::runtime_error. Ayrıca kullanıcılarım, what()kodlar gibi tanımlanmış minimum arabirime de güvenebilir .

Örneğin, kullanıcım hatalı argümanlar sunuyor, atmaktan daha uygun ne olurdu std::invalid_argument, değil mi? Bu yüzden başkalarının kodunda görmek std :: istisna henüz yaygın kullanımı ile birlikte: Neden daha ileri gitmek ve özel istisna sınıf (örneğin lib_foo_exception) ve ayrıca türetmek değil std::exception.

Düşünceler?


Takip ettiğimden emin değilim. Eğer devralan diye std::exceptionanlamına gelmez atmak bir std::exception. Ayrıca, ilk etapta std::runtime_errormiras alır std::exceptionve what()yöntem std::exceptiondeğil, gelir std::runtime_error. Ve böyle genel istisnalar atmak yerine kesinlikle kendi istisna sınıflarınızı yaratmalısınız std::runtime_error.
Vincent Savard

3
Fark, lib_foo_exceptionsınıfımdan türetildiğinde std::exception, kütüphane kullanıcısının sadece liberal olanı yakalamanın yanı sıra, lib_foo_exceptionsadece yakalayarak std::exceptionyakalayacağıdır. Bu yüzden benim kütüphane istisna kök sınıf std :: istisna miras gerekir .
Superlokkus

3
@LightnessRacesinOrbit Yani "... ek olarak", "Kaç tane yakalamanın yolu var lib_foo_exception?" Devralan ile std::exceptionsize gösterip yapabilirsiniz catch(std::exception)VEYA tarafından catch(lib_foo_exception). Doğan olmadan std::exception, bunu yakalamak istiyorsunuz ancak ve ancak yoluyla, catch(lib_foo_exception).
Superlokkus

2
@Superlokkus: Bir çeşit görmezden geliyoruz catch(...). Oradadır, çünkü dil düşündüğünüz vakaya (ve "yanlış davranış" kütüphanelerine) izin verir, ancak bu modern en iyi uygulama değildir.
Monica ile Hafiflik Yarışları

1
C ++ 'da istisna işleme tasarımının çoğu, daha kaba, daha genel catchsiteler ve aynı şekilde bir kullanıcı sonu operasyonunu modelleyen daha kaba işlemleri teşvik etme eğilimindedir . Genelleştirilmiş yakalama fikrini teşvik etmeyen dillerle karşılaştırırsanız std::exception&, örneğin, try/catchçok özel hatalarla ilgili olan ara bloklarla çok daha fazla kodları vardır , bu da yerleştirmeye başlarken istisna işlemenin genelliğini bir miktar azaltır. manuel hata işleme ve ayrıca olası tüm farklı hatalara daha güçlü bir vurgu.

Yanıtlar:


29

Tüm istisnalar devralınmalıdır std::exception.

Diyelim ki aramam gerekiyor ComplexOperationThatCouldFailABunchOfWays()ve fırlatabileceği istisnaları ele almak istiyorum. Her şey miras alırsa std::exception, bu kolaydır. Sadece tek bir catchbloğa ihtiyacım var ve what()ayrıntıları almak için standart bir arayüze ( ) sahibim .

try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
}

İstisnalar devralınmazsa std::exception, bu daha çirkinleşir:

try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
} catch (Exception& e) {
    cerr << e.Message << endl;
} catch (framework_exception& e) {
    cerr << e.Details() << endl;
}

Atmak runtime_errorya da atmak invalid_argumentiçin kendi std::exceptionalt sınıfları oluşturma ya karşı : Başparmak kuralı, belirli bir hata türünü diğer hatalardan farklı olarak ele almanız gerektiğinde (yani, ayrı bir catchbloğa ihtiyaç duyduğumda ) yeni bir alt sınıf tanıtmaktır .

  • Akla gelebilecek her hata türü için yeni bir istisna alt sınıfı tanıtırsam, bunları ayrı olarak ele almam gerekse bile, bu çok fazla sınıf çoğalması ekler.
  • Varolan alt sınıfları belirli bir şey ifade etmek için yeniden kullanırsam (yani, buradaruntime_error atılan genel çalışma zamanı hatasından farklı bir şey ifade ediyorsa ), varolan alt sınıfın diğer kullanımlarıyla çakışma riski taşırım.
  • Ben ise yok özellikle bir hata işlemek gerekiyor ve ben atıyorum o hata tam olarak mevcut standart kütüphanenin hatalardan birini (örneğin eşleşirse invalid_argument), o zaman var olan sınıf yeniden kullanın. Bu durumda yeni bir sınıf eklemek için fazla bir fayda görmüyorum. (C ++ Temel Yönergeleri burada benimle aynı fikirde değil - her zaman kendi sınıflarınızı kullanmanızı tavsiye ediyorlar.)

C ++ Çekirdek Kuralları daha fazla tartışma ve örneklerin sahiptir.


Tüm bu ve işaretleri! C ++ tuhaf.
SuperJedi224

2
@ SuperJedi224 ve tüm bu farklı harfler! İngilizce tuhaf.
johannes

Bu gerekçe benim için bir anlam ifade etmiyor. Bu ne değildir catch (...)(literal üç nokta ile) için nedir?
Makspm

1
@ Makspm catch (...), yalnızca atılanlarla herhangi bir şey yapmanız gerekmiyorsa yararlıdır . Örneğimde olduğu gibi, belirli bir hata mesajını göstermek veya günlüğe kaydetmek gibi bir şey yapmak istiyorsanız, bunun ne olduğunu bilmeniz gerekir.
Josh Kelley

9

Bir kütüphane kullanıcısı olarak, kütüphane işlevinin yalnızca standart kütüphane işlevleri kütüphane uygulamasında başarısız olduğunda std :: istisnaları atacağını ve bununla ilgili hiçbir şey yapamayacağını varsayarım.

Bu yanlış bir varsayım.

Standart istisna türleri "yaygın" kullanım için sağlanmıştır. Yalnızca standart kütüphane tarafından kullanılmak üzere tasarlanmamıştır .

Evet, her şeyi nihayetinde miras edin std::exception. Çoğu kez, bu devralma dahil edeceğiz std::runtime_errorya std::logic_error. Uyguladığınız istisna sınıfı için uygun olan ne varsa.

Bu elbette özneldir - birkaç popüler kütüphane, muhtemelen standart kütüphaneden kütüphaneleri ayırmak için standart istisna türlerini tamamen görmezden gelir. Şahsen bunun son derece bencil olduğunu düşünüyorum! Doğru olması çok daha zor olan istisnaları yakalamaktır.

Kişisel olarak konuşursak, sık sık a atarım std::runtime_errorve onunla yapılırım. Ancak bu, istisna sınıflarınızı ne kadar ayrıntılı hale getireceğinizle ilgili bir tartışmaya giriyor; bu, sorduğunuz şey değil.

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.