web-dev-qa-db-fra.com

C++ interceptant toutes les exceptions

Existe-t-il un équivalent c ++ de Java?

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

J'essaie de déboguer du code Java/jni qui appelle des fonctions Windows natives et la machine virtuelle continue de planter. Le code natif semble bien dans les tests unitaires et ne semble planter que lorsqu'il est appelé via jni. Un mécanisme générique de capture d'exception serait extrêmement utile.

203
Obediah Stane
try{
    // ...
} catch (...) {
    // ...
}

interceptera toutes les exceptions C++, mais cela devrait être considéré comme une mauvaise conception. Vous pouvez utiliser le nouveau mécanisme current_exception de c ++ 11, mais si vous ne pouvez pas utiliser c ++ 11 (systèmes de code hérités nécessitant une réécriture), vous ne pouvez utiliser aucun pointeur d'exception nommée pour obtenir un message ou un nom. . Vous voudrez peut-être ajouter des clauses catch distinctes pour les diverses exceptions que vous pouvez intercepter et ne capturer que tout ce qui se trouve en bas pour enregistrer une exception inattendue. Par exemple.:

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

Quelqu'un devrait ajouter qu'on ne peut pas attraper de "crash" en code C++. Ceux-ci ne jettent pas d'exceptions, mais font tout ce qu'ils veulent. Lorsque vous voyez un programme se bloquer, à cause par exemple d'un déréférencement null-pointeur, il a un comportement indéfini. Il n'y a pas de std::null_pointer_exception. Essayer d'attraper des exceptions ne va pas aider là-bas.

Juste au cas où quelqu'un lirait ce fil et pensait pouvoir obtenir la cause des plantages du programme. Un débogueur comme gdb devrait être utilisé à la place.

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

Notez que le ... à l'intérieur de la catch est un véritable Ellipsis, c'est-à-dire. trois points.

Toutefois, les exceptions C++ n'étant pas nécessairement des sous-classes d'une classe Exception de base, il est impossible de voir la variable d'exception générée lors de l'utilisation de cette construction.

54
Greg Hewgill

Voici comment vous pouvez procéder au reverse engineering du type d'exception à partir de catch(...) si vous en avez besoin (cela peut être utile lors de la capture d'inconnus d'une bibliothèque tierce) avec GCC:

#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;
}

et si vous pouvez vous permettre d’utiliser Boost vous pouvez rendre votre section de capture encore plus simple (à l’extérieur) et éventuellement multiplate-forme.

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

il n'est pas possible (en C++) d'attraper toutes les exceptions de manière portable. En effet, certaines exceptions ne sont pas des exceptions dans un contexte C++. Cela inclut des choses comme la division par zéro erreurs et autres. Il est possible de pirater et d'obtenir ainsi la possibilité de générer des exceptions lorsque de telles erreurs se produisent, mais ce n'est pas facile à faire et certainement pas facile à corriger de manière portable.

Si vous voulez intercepter toutes les exceptions STL, vous pouvez faire

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

Ce qui vous permettra d'utiliser e.what(), qui retournera un const char*, qui peut vous en dire plus sur l'exception elle-même. C'est la construction qui ressemble à la construction Java, sur laquelle vous avez le plus souvent posé la question.

Cela ne vous aidera pas si quelqu'un est assez stupide pour émettre une exception qui n'hérite pas de std::exception.

33
Clearer

En bref, utilisez catch(...). Cependant, notez que catch(...) est destiné à être utilisé avec throw; essentiellement:

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
}

C’est la bonne façon d’utiliser catch(...).

20
Mellester

il est possible de le faire en écrivant:

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

Mais il y a un risque très peu perceptible ici: vous ne pouvez pas trouver le type d'erreur exact qui a été généré dans le bloc try, utilisez donc ce type de catch lorsque vous êtes sûr que, quel que soit le type d'exception, le programme doit persister de la manière définie dans le bloc catch.

17
Infintyyy

Vous pouvez utiliser 

catch(...)

mais c'est très dangereux. Dans son livre Debugging Windows , John Robbins raconte une histoire de guerre à propos d’un bug vraiment méchant masqué par une commande catch (...). Vous feriez beaucoup mieux d'attraper des exceptions spécifiques. Attrapez tout ce que vous pensez que votre bloc try pourrait raisonnablement jeter, mais laissez le code lever une exception plus haut si quelque chose de vraiment inattendu se produit.

16
John D. Cook

Laissez-moi juste mentionner ceci ici: le Java

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

ne peut pas attraper toutes les exceptions! En fait, ce genre de chose s'est déjà produite auparavant, et cela provoque des insinuations; L'exception provient de Throwable. Donc, littéralement, pour attraper tout, vous ne voulez pas attraper des exceptions; vous voulez attraper Throwable.

Je sais que ça a l'air ridicule, mais quand vous avez passé plusieurs jours à essayer de comprendre d'où venait "l'exception non capturée" dans un code entouré d'un bloc try ... catch (Exception e) ", cela colle vous.

12
Paul Sonier

Eh bien, si vous voulez attraper toutes les exceptions pour créer un minidump par exemple ...

Quelqu'un a fait le travail sur Windows.

Voir http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus Dans l'article, il explique comment il a découvert comment intercepter toutes sortes d'exceptions et fournit un code qui fonctionne.

Voici la liste que vous pouvez attraper:

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

Et l'utilisation: CCrashHandler ch; Ch.SetProcessExceptionHandlers (); // faire ceci pour un thread ch.SetThreadExceptionHandlers (); // pour chaque thred


Par défaut, cela crée un minidump dans le répertoire en cours (crashdump.dmp)

6
Aftershock

Un mécanisme générique de capture des exceptions serait extrêmement utile.

Douteux. Vous savez déjà que votre code est cassé, car il se bloque. Manger des exceptions peut masquer cela, mais cela aboutira probablement à des bogues encore plus méchants et plus subtils. 

Ce que vous voulez vraiment, c'est un débogueur ...

3
Shog9
  1. Pouvez-vous exécuter votre application Java utilisant JNI à partir d'une fenêtre de console (lancez-la à partir d'une ligne de commande Java) pour voir s'il existe un rapport indiquant ce qui a pu être détecté avant le crash de la machine virtuelle. Lors de l'exécution directe en tant qu'application de fenêtre Java, il se peut qu'il manque des messages qui s'afficheraient si vous les exécutiez à partir d'une fenêtre de console.

  2. Deuxièmement, pouvez-vous stub votre implémentation JNI DLL pour montrer que les méthodes de votre DLL sont entrées à partir de JNI, que vous retournez correctement, etc.? 

  3. Au cas où le problème proviendrait d'une utilisation incorrecte de l'une des méthodes d'interface JNI à partir du code C++, avez-vous vérifié que des exemples simples de JNI se compilent et fonctionnent avec votre configuration? Je songe en particulier à utiliser les méthodes d'interface JNI pour convertir les paramètres en formats C++ natifs et convertir les résultats de fonctions en types Java. Il est utile de les stub pour vous assurer que les conversions de données fonctionnent et que vous ne vous trompez pas dans les appels de type COM dans l'interface JNI.

  4. Il y a d'autres choses à vérifier, mais il est difficile d'en suggérer sans en savoir plus sur vos méthodes Java natives et leur implémentation par JNI. Il n'est pas clair que la capture d'une exception du niveau de code C++ est liée à votre problème. (Vous pouvez utiliser l'interface JNI pour redistribuer l'exception sous forme Java, mais d'après ce que vous fournissez, cela ne vous aidera pas à comprendre.)

2
orcmid

Pour le vrai problème de ne pas pouvoir correctement déboguer un programme qui utilise JNI (ou le bogue n'apparaît pas lors de son exécution sous un débogueur):

Dans ce cas, il est souvent utile d’ajouter des wrappers Java autour de vos appels JNI (c’est-à-dire que toutes les méthodes natives sont privées et que vos méthodes publiques de la classe les appellent) qui effectuent des vérifications de base (vérifiez que tous les "objets" sont libérés et "objets" ne sont pas utilisés après la libération) ou la synchronisation (il suffit de synchroniser toutes les méthodes d'un DLL à une instance d'objet unique). Laissez les méthodes d'encapsulation Java consigner l'erreur et émettre une exception.

Cela aidera souvent à trouver la véritable erreur (ce qui est surprenant dans la plupart du temps dans le code Java qui n'obéit pas à la sémantique des fonctions appelées causant quelques méchants doubles-libérés ou similaires) plus facilement que d'essayer de déboguer un programme Java massivement parallèle dans un débogueur natif ...

Si vous en connaissez la cause, conservez le code dans vos méthodes d'emballage qui l'évite. Mieux vaut que vos méthodes d'encapsulation jettent des exceptions plutôt que votre code JNI plante la VM ...

1
mihi

Cela dépend vraiment de l’environnement du compilateur . Gcc ne les récupère pas .. Visual Studio et le dernier Borland que j’ai utilisé l’a fait.

La conclusion à propos des accidents est donc que cela dépend de la qualité de votre environnement de développement.

La spécification C++ Indique que catch (...) doit intercepter les exceptions, mais pas dans tous les cas.

Au moins d'après ce que j'ai essayé.

0
Jan