2013-03-28 16 views
5

Sanırım C++ ile uğraştığım iki miras hiyerarşim var. Biri std::exception (yeni hiyerarşi) ve diğerleri ise Exception (eski C++ Builder VCL temel kural dışı durum sınıfı) öğesinden devralınır. Ben hariç her iki tip atmak verebilecek kod dersek, bu gibi bir kod yazmak zorunda:Bir özel durum devralma hiyerarşisini diğerine sarın mı? - ya da bununla başa çıkmak için başka bir temiz yol var mı?

try { 
    // do stuff.... 
    Function1(); 
    Function2(); 
} catch (std::exception &ex) { 
    std::cout << "STL exception caught: " << ex.what() << std::endl; 
} catch (Exception &ex) { 
    std::cout << "Legacy exception caught: " << ex.Message.c_str() << std::endl; 
} catch (SomeOtherVendorLibraryException &ex) { 
    // etc. 
} 

sorun her arayan istisna her geçen türünü elde etmeye çalışmak için tüm bu yakalama maddelerini olması gerekir yani, C++ 'nın gerçek, zorlanmış özel durum taban sınıfına sahip olmasından dolayı, her şeyi bir örnek olarak kullanabilirsiniz (örneğin, C# System.Exception sınıfı). (catch (...), neleri yakaladığınızı bilmenin bir yolu olmadığından başlatıcı değildir ve erişim ihlali gibi bazı tehlikeli sistem istisnası da yakalanabileceği gibi daha iyi durumda bırakılabilir.)

Bu "eski" istisnaları, std::exception hiyerarşisinde bir sınıfa sarmak için. Üçüncü taraf istisnalarını kendi istisna sisteminize sarmak için yaptığınız bu kavram tamamen benzeri görülmemiştir. Örneğin, .NET Framework diğer sistemlerde geniş hata kümelerini (ör. COMException) sarar. İdeal olarak, böyle bir şey görmek istiyorum:

class LegacyException : public std::runtime_error { 
public: 
    // construct STL exception from legacy exception 
    LegacyException(const Exception &ex) : std::runtime_error(ex.Message.c_str()) {} 
}; 

try { 
    // In reality, this throw will happen in some function we have no control over. 
    throw Exception("Throwing legacy exception!"); 
} catch (std::exception &ex) { 
    // Ideally, the compiler would use the LegacyException constructor 
    // to cast the thrown Exception to a LegacyException, which ultimately 
    // inherits from std::exception. 
    std::cout << ex.what() << std::endl; 
} 

Anlaşılacağı üzere, durum yakalandı hiçbir zaman - bu pek yakalamak için derleyici büyü biraz soran olacaktır.

Eski bir istisnayı sarmak için yukarıdakilere benzer bir çözüm var mı ve bu hedeflere ulaşıyor mu?

  • Bir "yakalama" deyimi veya benzeri, genel kural dışı durum mantığının yalnızca bir kez yazılması gerekir.
  • Bir özel durum türünden diğerine dönüştürme mantığı merkezileştirilmelidir.
  • Mümkünse makroları engeller.
  • Lambda işlevleri kullanılmaz.
+1

Lambda işlevleri yok - C++ 11 özelliklerinden kaçınmanızın nedeni nedir? (Ben soruyorum yararlı olmayan lambda C++ 11 özellikleri olduğundan). –

+0

Ayrıca, hangi derleyiciyi hedefliyorsunuz? Microsoft derleyicileri, erişim ihlallerini yakalamak için "catch (...)" özelliğine neden olan bir özelliğe sahiptir, ancak bu özellik VS2005'den beri varsayılan olarak devre dışı bırakılmıştır. Bu gerekçelerle "yakala (...)" seçeneğini çıkarırsanız, seçeneklerinizi daha da azaltırsınız. –

+0

@JoeGauterin: C++ lambda işlevleri derleyicilerden biri tarafından desteklenmiyor, kodum hedefleniyor.Aksi takdirde, bu sorunu çözmek için onları 2 saniye içinde kullanacağım, eğer bu muazzam BCB derleyicisini kabul etmek için ikna edebilirsem: catch (...), daha sonra bir helper işlevini çağır ve std :: exception'u kabul eden bir lambda işlevini ilet. yardımcı. Yardımcı istisnayı yeniden düzenler, çeşitli türleri yakalar ve gerekirse dönüştürür, sonra lambda işlevini çağırır. Çok kötü C++ 11 kullanamıyorum. –

cevap

2

BC++ Builder ile çalıştıktan sonra aynı sorunu yerine getirdim ve makrolar o zamanki tek çözüm gibi görünüyordu.

"Temizleyici" (hum ...) çözümü büyük olasılıkla "çift yakalama" yöntemidir: iç deneme, eski durumunuzu standart bir sınıfa dönüştürür ve dış kısım aslında istisnayı işler.

Ben el altında kod yok (yıllar oldu) temelde ama aşağı kaynar:

#define DTRY try { try 
#define DCATCH catch (Exception& e) { throw LegacyException(e); } } catch 

DTRY { 
    ... 
} 
DCATCH(std::exception& e) { 
    // handle the exception 
} 

Evet çirkin biliyorum ama Borland ile çalıştı ne zaman bir şey bulamadık daha iyi. Gerçek şu ki, Borland aşırı derecede standart değildi ve o zamandan bu yana nasıl geliştiğini bilmiyorum, belki bugünlerde daha iyisini yapabilirsiniz. Umarım bu yine de yardımcı olur.

+0

Bugünlerde çok daha iyi, IMHO, ama şimdilik bununla yaşamak zorundayım. Diyelim ki, derleyiciyi çok yardımcı olacak bir şey için clang-tabanlı olarak değiştiriyorlar - ama birkaç ay önce kontrol ettiğimde 32-bit clang derleyici için bir zaman dilimi yoktu ... –

+0

@JamesJohnston Senin acını hissediyorum, benim Borland yılları da bir kabus oldu. ;) GCC'ye (ve çapraz platform yapmam gerektiğinde MinGW) geçiş benim kurtuluşumdu. – syam

İlgili konular