2014-09-19 23 views
5

Benim API'mda std::exception türetilmiş küçük bir özel durum hiyerarşisi var. Bir hata kodu, dosya, çizgi ve işlev sağlayan bir Exception taban sınıfım var. Diğer daha özel istisnalar ise Exception'dan türetilmiştir. Örneğin, türetilmiş bir sınıf, platforma özgü hata kodunu ve ayrıca hangi işlevin hata kodunu döndürdüğünü belirten bir alan ekler. Bu, system_error'un basitleştirilmiş bir sürümü gibidir, ancak C++ 11 özelliklerini kullanamıyorum (VS2005 ile çalışıp sıkışıp kaldım).Günlük biçimlendirmesindeki ayrıcalık istisnası

Bu özel durumları günlüğe kaydetme sınıfımla günlüğe kaydetmem gerekiyor. İstisnaların belirli bir biçimde kaydedilmesini istiyorum. Çeşitli çevrimiçi forumları okuduktan ve Boost's Error and Exception Handling Guidelines'u okuduktan sonra, her özel durumun what işlevinin veya Exception içindeki herhangi bir sanal işlevin, günlüğe kaydetme için özel durumu biçimlendirmek için uygun bir yer olduğunu düşünmüyorum. Bu nedenle, what işlevlerim yalnızca sınıfın adını döndürüyor.

İstisnai durumları yakalarken genellikle genellikle std::exception çok genel kural dışı durumları yakalamak ve kaydediciye aktarmak istiyorum. Tek istisnaları sık sık yakalamak istemiyorum çünkü API'dan (API'mnın kamusal kısmı C) kaçmaktan istisnaları önlemeye çalışıyorum ve ortaya çıkabilecek bazı istisnalar olabilir. Ben böyle bir kod önlemek istiyorum: benim günlük sınıfında Yani

try { /* blah */ } 
catch {DerivedException const& ex) { logger.log(ex); } 
... 
catch {Exception const& ex) { logger.log(ex); } 

, benim log işlevi std::exception argüman kabul eder. Daha sonra, parametreyi çeşitli özel durum sınıflarıyla karşılaştırmak, uygun türe dökmek ve sonra bu tür bir özel durum için özelleştirilmiş bir günlük kaydı işlevini çağırmak için typeid kullanır. Bu aslında in this other post tarif edilen aynı tekniktir. dynamic_cast herhangi bir geçerli downCast için başarılı olabilir çünkü

Ben typeid yerine dynamic_cast kullanın ve kod bakım amacıyla, gerçekten log işlevinde benim if tabloların sırası önemli istemiyoruz.

Bu iyi bir tasarım mı? Böyle typeid kullanarak bana yanlış geliyor, ama bunu yapmak için geçerli nedenler olduğunu düşünüyorum. “Civcivte” çok fazla istisna eylemi görmedim, çünkü öncelikle C ile çalışıyoruz, bu yüzden konuya çok fazla yaklaşım görmedim. Farkında olmaları gereken günlük biçimlendirmelerinden özel durumları ayırmanın başka yolları var mı?

DÜZENLEME: Ben ziyaretçi desen kullanarak öneri aldı, ama benim duruma uyarladı
uygulamaya karar ne. std::exception'u yakalamak istedim, çünkü bunlar kendime ait olduğu kadar atılabilir, ancak günlük mesajını istisna tipine göre biçimlendirebilir.

Her özel durum sınıfım Exception sınıfımdan türetilir ve sanal işlevi accept uygular. visit işlevlerini sağlayan bir ExceptionVisitor arabirimini uygulayan bir ExceptionLogger sınıfı oluşturdum.

LogFile sınıfı ExceptionLogger bir örneğini, hem de bir std::exception parametre alır onun log fonksiyonunun bir aşırı vardır. log işlevinde, temel türüme, Exception'u deneyin. Başarılırsa, özel durumun accept işlevini ararım, aksi takdirde doğrudan ExceptionLogger::visit(std::exception const&) işlevini çağırırım.std::exception, accept işlevimi uygulamıyorsa, dynamic_cast'a ihtiyacım vardı, böylece daha ayrıntılı günlüğe kaydetmenin mümkün olup olmadığını belirleyebilirdim.

yerine typeid kontrol if tabloların bir dizi bunu seçtik çünkü:

  1. Bu bir sürdürücü Yeni bir istisna bundan türetilen eklerse ben
  2. gelecek bakıcılarına başvurabilir adlandırılmış tasarım deseni Exception tabanımdan ancak bu istisna için yeni bir visit işlevini uygulamayı unuttuğum için, Exception tabanına uygulanan bir günlüğü kaydetmeye devam ediyorum - bir dosya, satır numarası ve işlev.

    Ben if tabloların dizi uygulamaya olsaydı

    , ben what sonuçlarını yazdırmak için adildir std::exception Günlüğün çalışma, geri düşmek ederdi, yoksa bir Exception bir dynamic_cast denedim olabilir .

    Elbette bu durumda derleyici hatası tercih ediyorum.

+1

Alternatif, Ziyaretçi kalıbını uygulamak olacaktır. –

+0

@DDrmmr - Ziyaretçi desenini kullanarak sona erdim. Bunu bir cevap haline getirin ve kabul edildi olarak işaretleyeceğim. –

cevap

1

Daha basit bir çözüm sizin merkez biçimlendirme stilini istisnayı yeniden atması için (ayrıca this answer bakınız). Ardından, her özel durum türünü yakalayabilir ve biçimlendirebilirsiniz.

class Exception : public std::exception {}; 
class DerivedException : public Exception {}; 
void LogThrownException(); 

void DoSomething() 
{ 
    try 
    { 
     // Do something, might throw ... 
    } 
    catch (...) 
    { 
     LogThrownException(); 
    } 
} 

void LogThrownException() 
{ 
    try 
    { 
     throw; 
    } 
    // Order is important to catch all derived types. 
    // Luckily the compiler should warn, if a type is hidden. 
    catch (DerivedException&) 
    { 
     std::cout << "DerivedException"; 
    } 
    catch (Exception&) 
    { 
     std::cout << "Exception"; 
    } 
    catch (std::exception&) 
    { 
     std::cout << "std::exception"; 
    } 
    // ... 
    catch (...) 
    { 
     std::cout << "Unknown\n"; 
    } 
} 
+0

diğer cevap istediğiniz zaman silinmiş olabilir, bu nedenle, burada açıklıyor – manetsus

+0

ipucu için teşekkür ederiz, cevabımı düzenledim. Burada yeniyim ve çoğaltmanın daha iyi olmadığını düşündüm. – Djan

+0

Bu daha basit bir çözümdür. Maalesef bunu uygulamak için çok geç ama bunu seviyorum ve geleceği akılda tutmaya devam edeceğim. –