C ++ tüm istisnaları yakalar


244

Java'nın c ++ eşdeğeri var mı

try {
    ...
}
catch (Throwable t) {
    ...
}

Yerel windows işlevlerini çağıran Java / jni kodu hata ayıklamaya çalışıyorum ve sanal makine çökmeye devam ediyor. Yerel kod birim testinde iyi görünür ve yalnızca jni aracılığıyla çağrıldığında çöküyor gibi görünür. Genel bir istisna yakalama mekanizması son derece yararlı olacaktır.



2
Çoğu kilitlenmenin C ++ istisnalarından kaynaklanmadığını unutmayın. Tüm istisnaları yakalayabilirsiniz, ancak bu birçok çökmeyi engellemez.
Mooing Duck

Yanıtlar:


335
try{
    // ...
} catch (...) {
    // ...
}

tüm C ++ istisnalarını yakalar, ancak kötü tasarım olarak kabul edilmelidir. C ++ 11'in yeni current_exception mekanizmasını kullanabilirsiniz, ancak c ++ 11'i (yeniden yazma gerektiren eski kod sistemleri) kullanma yeteneğiniz yoksa, bir ileti veya ad almak için adlandırılmış istisna işaretçiniz yok . Yakalayabileceğiniz çeşitli istisnalar için ayrı yakalama cümleleri eklemek ve yalnızca beklenmedik bir istisna kaydetmek için alt kısımdaki her şeyi yakalamak isteyebilirsiniz. Örneğin:

try{
    // ...
} catch (const std::exception& ex) {
    // ...
} catch (const std::string& ex) {
    // ...
} catch (...) {
    // ...
}

68
Const referansı ile istisnaları yakalamak iyi bir uygulamadır. Olduğu gibi: catch (std :: exception const & ex) {/ * ... * /}
coryan

12
@coryan: Neden const referansı ile yakalamak iyi bir uygulama?
Tim MB

19
Gereksiz kopyalardan kaçınmak bir faydadır.
Greg D

21
-1: "C ++ 'daki tüm istisnaları yakalaması" önerisi yanıltıcıdır. Try bloğunun içinde sıfır hata ile bir bölme oluşturmayı deneyin. Yakalanmayan bir istisna oluşturacağını göreceksiniz, ancak kod açıkça C ++ 'dadır. Bunun "tüm C ++ istisnalarını yakalayacağını" ve daha sonra sınırlı kullanışlılığa ilişkin notlara yapılandırılmış istisnalardan biraz bahsedeceğini belirtmek daha yararlı olacaktır.
omatai

42
@omatai: Düzeltildi, tüm C ++ istisnalarını yakalayacak. Sıfıra bölme tanımsız bir davranıştır ve bir C ++ istisnası oluşturmaz.
Mooing Duck

151

Birisi, C ++ kodunda "çökmeleri" yakalayamayacağını eklemelidir. İstisnalar atmazlar, istedikleri her şeyi yaparlar. Boş gösterici dereference dediği için bir programın çöktüğünü gördüğünüzde, tanımsız davranış yapıyor. Yok std::null_pointer_exception. İstisnaları yakalamaya çalışmak burada yardımcı olmaz.

Birisi bu konuyu okuyor ve program çökmelerinin nedenini alabileceğini düşünüyor. Bunun yerine gdb gibi bir hata ayıklayıcı kullanılmalıdır.


4
Shy'nin belirttiği gibi, VC derleyicisi ile mümkündür. İyi bir fikir değil, ama mümkün.
Shog9 1

7
evet SEH ile. ama sane standart c ++ teknikleri ile değil :) iyi pencerelere sopa neredeyse her şeyi yapabilirsiniz :)
Johannes Schaub - litb

1
Mmm ... bu çöplük için teşekkürler. Boş gösterici istisnalarımın neden yakalanmadığının cevabını arıyordum!
Dalin Seivewright

10
Windows'ta SEH ve günümüzde kullanılan sistemlerin büyük çoğunluğunu kapsayan POSIX sistemlerinde sinyal (2) / sigaction (2) ile segfaultları yakalayabilirsiniz, ancak istisna işleme gibi, normal akış kontrolü için kullanılması gereken bir şey değildir. Daha çok "ölmeden önce faydalı bir şeyler yapın".
Adam Rosenfield

1
@AdamRosenfield try { .. } catch(...) { ... }sinyal / sigaction kullanarak yakalamak için uygulayana kadar , ben "yakalamak" olarak adlandırmaz :) :) Bir sinyal işleyicisi, programcı için kilitlenme kodunun nerede olduğunu bilmek nispeten zor (konuşuyorum) bunu programlı olarak algılama hakkında), try / catch ile karşılaştırıldığında.
Johannes Schaub - litb

72

catch(...)GCC ile gereksinim duyduğunuzda (üçüncü taraf kitaplığından bilinmeyenleri yakalarken yararlı olabilir) istisna türünü içerden tersine yapılandırabilirsiniz:

#include <iostream>

#include <exception>
#include <typeinfo>
#include <stdexcept>

int main()
{
    try {
        throw ...; // throw something
    }
    catch(...)
    {
        std::exception_ptr p = std::current_exception();
        std::clog <<(p ? p.__cxa_exception_type()->name() : "null") << std::endl;
    }
    return 1;
}

ve Boost'u kullanmayı göze alabiliyorsanız , yakalama bölümünüzü daha basit (dışarıdan) ve potansiyel olarak çapraz platform haline getirebilirsiniz

catch (...)
{
    std::clog << boost::current_exception_diagnostic_information() << std::endl;
}

58
try {
   // ...
} catch (...) {
   // ...
}

...İçinde catchgerçek bir üç nokta olduğunu unutmayın . üç nokta.

Ancak, C ++ özel durumlarının bir temel Exceptionsınıfın alt sınıfları olması gerekmediğinden , bu yapı kullanılırken atılan özel durum değişkenini gerçekten görmenin bir yolu yoktur.


24
C ++ 11'de: try (std :: string (). At (1); // bu bir std :: out_of_range} üretir (...) {eptr = std :: current_exception (); // yakalama}
Mohammad Alaggan

2
@bfontaine: Evet, ama açıkçası C ++ sözdizimi olmayan catchbir açıklamada ( // ...) mevcut kod yer tutucusundan belirleyiciyi ayırt etmeyi söyledim .
Greg Hewgill

1
@GregHewgill: evet, sadece tipografik nitpicking'dı.
bfontaine

1
@bfontaine: Yeterince adil. :)
Greg Hewgill

44

tüm istisnaları taşınabilir bir şekilde yakalamak mümkün değildir (C ++ ile). Bunun nedeni, bazı istisnaların bir C ++ bağlamında istisnalar olmamasıdır. Buna sıfır hatalara bölünme ve diğerleri dahildir. Bu hatalar meydana geldiğinde hacklemek ve böylece istisnalar atmak mümkündür, ancak yapmak kolay değildir ve kesinlikle taşınabilir bir şekilde elde etmek kolay değildir.

Tüm STL istisnalarını yakalamak istiyorsanız,

try { ... } catch( const std::exception &e) { ... }

Hangi kullanmanıza izin verecek e.what(), hangi bir döndürecektir const char*, bu size istisna hakkında daha fazla bilgi verebilir. Bu, en çok sorduğunuz Java yapısına benzeyen yapıdır.

Birisi miras almayan bir istisna atacak kadar aptalsa bu size yardımcı olmaz std::exception.


2
bu neden en üstte değil?
Ivan Sanz-Carasa

31

Kısacası kullanın catch(...). Bununla catch(...)birlikte, throw;temel olarak aşağıdakilerle birlikte kullanılması gerektiğini unutmayın :

try{
    foo = new Foo;
    bar = new Bar;
}
catch(...)       // will catch all possible errors thrown. 
{ 
    delete foo;
    delete bar;
    throw;       // throw the same error again to be handled somewhere else
}

Kullanmanın doğru yolu budur catch(...).


6
bu istisna durumlarını otomatik olarak ele alan bellek yönetimi için RAII kullanmak daha iyidir.
paykoob

1
@paykoob Bu, yeni bir foo yaratmayı başardığınız ancak bir çubukta başarısız olduğu durumları nasıl ele alır. Veya bar oluşturucu bir dosyayı açmak için trys ama başarısız ve bu nedenle atar. o zaman sarkan bir foo ile sonuçlanabilir
Mellester

2
@MelleSterk Bu durumda yığın hala temizlenmez mi, hangisinin Fooyıkıcısı çalışır? Bunun RAII'nin bütün mesele olduğunu düşündüm. Ancak, Fooyalnızca Fooyığında oluşturmak yerine bir işaretçiye ihtiyacınız varsa , işaretçiyi yığında bildirilen başka bir şeye sarmanız gerekir.
reirab

evet otomatik foo = std :: make_unique <Foo> (); otomatik çubuk = std :: make_unique <Bar> (); // istisna güvenlidir ve sızmaz, yakalanmaz (...)
paulm

Bu cevap sadece tartışma başladığında oylamayı hak ediyor :)
Cristik

21

bunu yazarak yapmak mümkündür:

try
{
  //.......
}
catch(...) // <<- catch all
{
  //.......
}

Ancak burada çok fark edilmeyen bir risk var: tryblokta atılan kesin hata türünü bulamıyorsunuz , bu nedenle catchistisna türü ne olursa olsun, programın devam etmesi gerektiğinden emin olduğunuzda bu tür catchblokta tanımlanan şekilde .


31
Umarım, üstün bir cevap verildikten yaklaşık 5 yıl sonra bir soruyu cevaplamak için bir çeşit rozetiniz olur!


18

Kullanabilirsiniz

catch(...)

ama bu çok tehlikeli. Windows Hata Ayıklama kitabında John Robbins, catch (...) komutuyla maskelenen gerçekten kötü bir hata hakkında bir savaş hikayesi anlatıyor. Belirli istisnaları yakalamaktan çok daha iyisiniz. Deneme bloğunuzun makul bir şekilde atılabileceğini düşündüğünüz her şeyi yakalayın, ancak gerçekten beklenmedik bir şey olursa kodun bir istisna atmasına izin verin.


1
Bunların bazı kullanımlarını yakaladım ve o aşamada bazı tomruklarda biberle kapladım. İstisna dışında hiçbir şey yapmamak kesinlikle sorun istiyor.
jxramos

15

Burada biraz bahsedeyim: Java

try 
{
...
}
catch (Exception e)
{
...
}

tüm istisnaları yakalayamayabilir! Aslında daha önce böyle bir şey oldu, ve bu çok kışkırtıcı; İstisna, Throwable'dan türetilir. Kelimenin tam anlamıyla, her şeyi yakalamak için İstisnaları yakalamak istemezsiniz; Throwable'ı yakalamak istiyorsun.

Kulağa nitpicky geldiğini biliyorum, ama birkaç gün geçirdikten sonra "yakalanmayan istisna" bir try ... catch (Exception e) bloğu ile çevrili koddan nereden geldiğini anlamaya çalıştığınızda, sen.


2
Tabii ki, asla Hata nesnelerini yakalamamalısınız - eğer onları yakalamanız gerekiyorsa, bunlar İstisnalar olacaktır. Hata nesneleri, yığın alanı tükenmesi gibi tamamen ölümcül şeylerdir
SCdF

1
Çoğu zaman iyi çalışma zamanı istisnaları GoodProgrammerExpected istisnaları !!!
OscarRyz

3
Bir şeyleri öldürmesine izin vermek yerine bir catch (Throwable) bloğu nedeniyle bir OutOfMemoryError yakalamanın neden olduğu gerçekten ciddi bir
hatayla karşılaştık

1
Elbette catch(Exception)Java'daki tüm istisnaları yakalayamayabilir, C # ... ile karıştırıyorsunuz Java = catch(Thowable), C # = catch(Exception). Onların kafasını karıştırmayın.
Şef Firavun

2
@OscarRyz Kulağa benziyor CoderMalfunctionError(aslında gerçek bir Java Erroralt sınıfı ... ne gibi göründüğü anlamına gelmiyor.)
reirab

9

Örneğin, bir mini döküm oluşturmak için tüm istisnaları yakalamak isterseniz ...

Birisi işi Windows'ta yaptı.

Bkz. Http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus Makalede, her türlü istisnayı nasıl yakalayacağını nasıl öğrendiğini ve çalışan kodu sağladığını açıklıyor.

Yakalayabileceğiniz liste:

 SEH exception
 terminate
 unexpected
 pure virtual method call
 invalid parameter
 new operator fault 
 SIGABR
 SIGFPE
 SIGILL
 SIGINT
 SIGSEGV
 SIGTERM
 Raised exception
C++ typed exception

Ve kullanımı: CCrashHandler ch; ch.SetProcessExceptionHandlers (); // bunu bir iş parçacığı için yapın ch.SetThreadExceptionHandlers (); // her bir atış için


Varsayılan olarak, bu geçerli dizinde bir mini döküm oluşturur (crashdump.dmp)


4

Genel bir istisna yakalama mekanizması son derece yararlı olacaktır.

Şüpheli. Kodunuzun bozuk olduğunu zaten biliyorsunuz, çünkü kilitleniyor. İstisnalar yemek bunu maskeleyebilir, ancak bu muhtemelen daha nahoş, daha ince böceklerle sonuçlanır.

Gerçekten istediğiniz bir hata ayıklayıcı ...


13
Kabul etmiyorum, gerçek zamanlı uygulamalarda bilinmeyen bir istisna yakalamayı, bir günlüğe herhangi bir şey yazmayı / uygulamanın çökmesine izin vermek yerine bazı genel hata eylemlerini izlemeyi tercih ettiğim birçok vaka var .
f0ster

3
Daha doğrusu size vakaların ediyoruz düşünme şüpheli olabilir elverişli yığın çöpe atılan veya bellek bitkin ve jenerik hata işleme ya başarılı olacak değil mi olduğunun, bunun görmezden eylem bazı genel hata potansiyeli mevcuttur. Geri alabileceğiniz hataları yakalamada yanlış bir şey yoktur , ancak IMHO bir catch-all gerçekten sadece (ayrı yığın, önceden ayrılmış bellek), program sonlandırılmadan hemen önce dikkatlice yazılmış mantık olarak var olmalıdır; Sorunun ne olduğunu bilmiyorsanız, sorunun çözülebileceğinden emin olamazsınız.
Shog9

1
Yani, programın nerede çöktüğünü ve umarım nedenini anlamak için çalışma zamanı sırasında oluşturduğunuz bazı günlükleri çözen bir sinyal işleyici yükler.
Daha net

3
  1. JVM çökmeden önce tespit edilmiş olabilecek herhangi bir rapor olup olmadığını görmek için JNI kullanan Java uygulamanızı bir konsol penceresinden çalıştırabilir (bir java komut satırından başlatabilirsiniz). Doğrudan bir Java penceresi uygulaması olarak çalıştırırken, bunun yerine bir konsol penceresinden koştuğunuzda görüntülenecek mesajlar eksik olabilir.

  2. İkincisi, DLL'nizdeki yöntemler JNI girildiğini göstermek için JNI DLL uygulama saplama, düzgün iade, vb?

  3. Sorunun C ++ kodundan JNI arabirimi yöntemlerinden birinin yanlış kullanımı ile ilgili olması durumunda, bazı basit JNI örneklerinin derlendiğini ve kurulumunuzla çalıştığını doğruladınız mı? Özellikle parametreleri yerel C ++ biçimlerine dönüştürmek ve Java türlerine işlev sonuçları dönüm için JNI arabirimi yöntemlerini kullanarak düşünüyorum. Veri dönüşümlerinin çalıştığından ve JNI arayüzüne COM benzeri çağrılarda haywire gitmediğinizden emin olmak için bunları saplamak yararlıdır.

  4. Kontrol edilecek başka şeyler de var, ancak yerel Java yöntemlerinizin ne olduğu ve JNI uygulamasının ne yapmaya çalıştığı hakkında daha fazla bilgi sahibi olmadan önermek zor. C ++ kod düzeyinden bir istisna yakalamanın sorununuzla ilgili olduğu açık değildir. (İstisnayı Java olarak yeniden oluşturmak için JNI arayüzünü kullanabilirsiniz, ancak bunun size yardımcı olacağı açık değildir.)


2

JNI kullanan bir programda düzgün hata ayıklayamama ile ilgili gerçek sorun için (veya hata ayıklayıcı altında çalıştırıldığında hata görünmüyor):

Bu durumda, bazı temel akıl sağlığı kontrolleri yapan (tüm "nesnelerin" serbest bırakıldığını ve "nesneleri" kontrol eden JNI çağrılarınızın etrafına Java sarmalayıcıları eklemenize yardımcı olur (yani, tüm yerel yöntemler özeldir ve sınıftaki genel yöntemler bunları çağırır). serbest bırakıldıktan sonra kullanılmaz) veya senkronizasyon (tüm yöntemleri tek bir DLL'den tek bir nesne örneğine senkronize edin). Java sarıcı yöntemlerinin hatayı günlüğe kaydetmesine ve bir istisna atmasına izin verin.

Bu genellikle gerçek hatayı bulmaya yardımcı olur (şaşırtıcı bir şekilde çoğunlukla, bazı kötü çift serbestliklere veya benzerlerine neden olan çağrılan işlevlerin anlamlarına uymayan Java kodundadır), büyük bir paralel Java programında hata ayıklamaya çalışmaktan daha kolay yerel hata ayıklayıcı ...

Nedeni biliyorsanız, kodu önleyen sarmalayıcı yöntemlerinde saklayın. Sarma yöntemlerinizin, VM'yi kilitleyen JNI kodunuzdan daha iyi istisnalar atması daha iyi ...


1

Bu gerçekten derleyici ortamına bağlıdır. gcc bunları yakalamaz. Visual Studio ve kullandığım son Borland yaptı.

Dolayısıyla, çökmelerle ilgili sonuç, geliştirme ortamınızın kalitesine bağlı olmasıdır.

C ++ belirtimi, catch (...) öğesinin herhangi bir istisnayı yakalaması gerektiğini, ancak her durumda geçerli olmadığını söylüyor.

En azından denediğim kadarıyla.


1

Farkında olmak

try{
// ...
} catch (...) {
// ...
}

yalnızca dil düzeyindeki istisnaları yakalar, diğer düşük düzeydeki istisnaları / hataları yakalar Access Violationve Segmentation Faultyakalanmaz.


Segmentasyon Hatası gibi şeyler aslında istisna değildir, sinyallerdir; bu nedenle, bunları tipik istisnalar gibi yakalayamazsınız. Ancak, gibi bazı çözüm yolu vardır bu .
MAChitgarha
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.