Share via


Erreurs et gestion des exceptions C++ (moderne)

En C++ moderne, dans la plupart des scénarios, la meilleure façon de signaler et de gérer les erreurs de logique et d'erreurs d'exécution consiste à utiliser les exceptions.Ceci est particulièrement vrai lorsque la pile peut contenir plusieurs appels de fonction entre la fonction qui détecte l'erreur et la fonction qui possède le contexte de savoir comment le gérer.Les exceptions fournissent un moyen formel et bien défini pour le code qui détecte des erreurs pour transmettre les informations de la pile des appels.

Erreurs de programme sont généralement divisés en deux catégories : les erreurs logiques qui sont provoquées par programmation des erreurs, par exemple, une erreur « index hors limites » et les erreurs d'exécution qui sont la volonté du programmeur, par exemple, une erreur « service non disponible du réseau ».Dans la programmation de style c et COM, le rapport d'erreurs est géré en retournant une valeur qui représente un code d'erreur ou un code d'état pour une fonction particulière, soit en définissant une variable globale que l'appelant peut éventuellement récupérer après chaque appel de fonction pour voir si les erreurs ont été signalés.Par exemple, programmation COM utilise la valeur de retour HRESULT pour communiquer des erreurs à l'appelant, et l'API Win32 a la fonction GetLastError pour récupérer la dernière erreur a été signalée par la pile des appels.Dans ces deux cas, il incombe à l'appelant pour reconnaître le code et y répondre convenablement.Si l'appelant ne traite pas explicitement le code d'erreur, le programme peut s'arrêter sans avertissement, ou continuer à s'exécuter avec des données erronées et produire des résultats incorrects.

Les exceptions C++ modernes sont préférables pour les raisons suivantes :

  • Une exception oblige le code appelant pour reconnaître une condition d'erreur et le gérer.Les exceptions non gérées arrêter l'exécution du programme.

  • Une exception atteint le point dans la pile des appels qui peut gérer l'erreur.Fonctions intermédiaires peuvent laisser l'exception se propager.Ils n'ont pas à coordonner avec d'autres calques.

  • Le mécanisme le déroulement de pile d'exception détruit tous les objets dans la portée en fonction de règles bien définies et après qu'une exception est levée.

  • Une exception permet une séparation nette entre le code qui détecte l'erreur et le code qui gère l'erreur.

L'exemple simplifié suivant illustre la syntaxe nécessaire pour lever et intercepter des exceptions en C++.

 
#include <stdexcept>
#include <limits>
#include <iostream>
 
using namespace std;
class MyClass
{
public:
   void MyFunc(char c)
   {
      if(c < numeric_limits<char>::max())
         throw invalid_argument("MyFunc argument too large.");
      //...
   }
};

int main()
{
   try
   {
      MyFunc(256); //oops!
   }
 
   catch(invalid_argument& e)
   {
      cerr << e.what() << endl;
      return -1;
   }
   //...
   return 0;
}

Les exceptions C++ semblables à celles de langages tels que c# et Java.Dans la try bloquer, si une exception est levée sera interceptée par le premier associés catch bloc dont le type correspond à celui de l'exception.En d'autres termes, l'exécution passe à partir de la throw instruction pour la catch instruction.Si aucun bloc catch utilisable est trouvé, std::terminate est appelée et le programme se ferme.En C++, n'importe quel type peut être levé ; Toutefois, nous recommandons que vous levez un type qui dérive directement ou indirectement de std::exception.Dans l'exemple précédent, le type d'exception, invalid_argument, est défini dans la bibliothèque standard dans la <stdexcept> fichier d'en-tête.C++ ne fournit pas et ne nécessite pas un finally bloc pour vous assurer que toutes les ressources sont libérées si une exception est levée.L'acquisition de ressources est l'idiome d'initialisation (RAII), qui utilise des pointeurs intelligents, fournit les fonctionnalités requises pour le nettoyage des ressources.Pour plus d'informations, consultez Comment : Conception de la sécurité d'exception.Pour plus d'informations sur le mécanisme de désempilage C++, consultez Exceptions et déroulement de pile en C++.

Directives de base

Gestion des erreurs robuste est un défi dans tout langage de programmation.Bien que les exceptions fournissent plusieurs fonctionnalités qui prennent en charge de la bonne gestion d'erreur, ils ne peuvent pas faire tout le travail pour vous.Pour profiter des avantages du mécanisme d'exception, conserver les exceptions à l'esprit lorsque vous concevez votre code.

  • Utilisation d'assertions pour vérifier les erreurs qui ne devraient jamais se produire.Utiliser les exceptions pour détecter les erreurs qui pourraient se produire, par exemple, les erreurs de validation des entrées sur les paramètres des fonctions publiques.Pour plus d'informations, consultez Exceptions VS. Assertions.

  • Utilisez des exceptions lorsque le code qui gère l'erreur peut être séparé par un ou plusieurs appels de fonction intermédiaires à partir du code qui détecte l'erreur.Pensez à utiliser les codes d'erreur à la place dans des boucles de performances critiques lorsque le code qui gère l'erreur est étroitement couplé au code qu'il détecte.Pour plus d'informations sur quand ne pas utiliser les exceptions, voir When Not to Use Exceptions.

  • Pour chaque fonction qui peut lever ou propager une exception, fournir une des trois exceptions garanties : la garantie forte, la garantie de base ou la garantie nothrow (noexcept).Pour plus d'informations, consultez Comment : Conception de la sécurité d'exception.

  • Lever des exceptions par valeur, leur capture le piège par référence.Ne catch ne peut pas gérer.Pour plus d'informations, consultez Règles sur la levée et l'interception d'exceptions (C++).

  • N'utilisez pas de spécifications d'exceptions, qui sont déconseillées dans C ++ 11.Pour plus d'informations, consultez Exception specifications and noexcept.

  • Utiliser des types d'exception standard library lorsqu'ils s'appliquent.Dériver des types d'exceptions personnalisées à partir de la classe exception hiérarchie.Pour plus d'informations, consultez Comment : Utilisez des objets exception standard de bibliothèque.

  • Ne pas autoriser d'exceptions à évacuation destructeurs ou des fonctions de libération de mémoire.

Exceptions et performances

Le mécanisme d'exception possède une performance très minime coût si aucune exception n'est levée.Si une exception est levée, le coût de la traversée de la pile et le déroulement sont à peu près comparable au coût d'un appel de fonction.Structures de données supplémentaires sont requises pour suivre la pile des appels après une try bloc est entré, et des instructions supplémentaires sont requises pour dérouler la pile si une exception est levée.Toutefois, dans la plupart des scénarios, le coût des performances et l'encombrement mémoire n'est pas significatif.L'effet néfaste d'exceptions sur les performances est susceptible d'être significatif uniquement sur les systèmes très limité en mémoire, ou de performances critiques boucles où une erreur est susceptible de se produire régulièrement et le code pour gérer il est étroitement couplé au code qui signale.En tout cas, il est impossible de connaître le coût réel des exceptions sans profilage et de mesure.Même dans les rares cas lorsque le coût est important, vous pouvez le peser contre l'exactitude accrue, la facilité de maintenance plus facile et autres avantages fournis par une politique d'exception bien conçue.

Exceptions VS. assertions

Exceptions et les assertions sont deux mécanismes distincts pour la détection des erreurs d'exécution dans un programme.Utilisation d'assertions pour tester des conditions au cours du développement ne devrait jamais être true si tout votre code est correct.Aucun point de gestion d'une telle erreur à l'aide d'une exception, car l'erreur indique que quelque chose dans le code doit être fixé et ne représente pas une condition que le programme doit récupérer au moment de l'exécution.Une assertion interrompt l'exécution à l'instruction afin que vous pouvez inspecter l'état du programme dans le débogueur ; une exception poursuit l'exécution à partir du premier gestionnaire catch appropriée.Utiliser les exceptions pour vérifier les conditions d'erreur qui peuvent se produire au moment de l'exécution, même si votre code est correct, par exemple, « fichier introuvable » ou « mémoire insuffisante. » Vous pouvez souhaiter de remédier à ces conditions, même si la récupération juste génère un message dans un journal et termine le programme.Vérifiez toujours les arguments des fonctions publiques en utilisant des exceptions.Même si votre fonction est exempt d'erreur, vous peut-être pas le contrôle complet sur les arguments qui lui peut passer un utilisateur.

Exceptions C++ et les exceptions SEH de Windows

Les programmes c et C++ peuvent utiliser la mécanisme (SEH) dans le système d'exploitation Windows de gestion structurée des exceptions.Les concepts de SEH semblables à celles dans les exceptions C++, sauf que SEH utilise le __try, __except, et __finally construit au lieu de try et catch.Dans Visual C++, les exceptions C++ sont implémentées pour SEH.Toutefois, lorsque vous écrivez du code C++, utilisez la syntaxe d'exception C++.

Pour plus d'informations concernant SEH, consultez Gestion structurée des exceptions (C++).

Noexcept et les spécifications d'exceptions

Spécifications d'exceptions ont été introduites dans C++ comme un moyen de spécifier une fonction peut lever les exceptions.Cependant, les spécifications d'exceptions s'est révélé problématiques dans la pratique et sont déconseillées dans le C ++ 11 avant-projet de norme.Nous vous recommandons que vous n'utilisez pas les spécifications d'exceptions à l'exception de throw(), qui indique que l'exception n'autorise aucune exceptions comme caractère d'échappement.Si vous devez utiliser les spécifications d'exceptions du type throw(type), sachez que Visual C++ s'écarte de la norme de certaines manières.Pour plus d'informations, consultez Spécifications d'exception.Le noexcept spécificateur est introduit dans C ++ 11 comme alternative pour throw().

Voir aussi

Concepts

Comment : Interface entre le code exceptionnel et non Exceptionnel

Autres ressources

Accueil vers C++ (C++ moderne)

Guide de référence du langage C++

Référence de la bibliothèque C++ standard