web-dev-qa-db-fra.com

Pourquoi std :: exception intercepte mon exception avant std :: bad_alloc?

Problème : J'utilise à la fois std :: exception et std :: bad_alloc pour intercepter l'exception. Quelque chose ne va pas dans l'ordre des prises d'essai que j'utilise. J'ai joint un exemple de code pour référence.

Attendu : Si mon erreur est bad_alloc, l'exception bad_alloc est renvoyée.

Observé : Mon erreur est bad_alloc, mais une exception est levée.

Exemple de code :

#include "stdafx.h"
#include <iostream>
#include <exception>

using namespace std;

void goesWrong()
{
    bool error1Detected = true;
    bool error2Detected = false;

    if (error1Detected)
    {
        throw bad_alloc();
    }

    if (error2Detected)
    {
         throw exception();
    }
}

int main()
{
    try
    {
        goesWrong();
    }
    catch (exception &e)
    {
        cout << "Catching exception: " << e.what() << endl;
    } 
    catch (bad_alloc &e)
    {
        cout << "Catching bad_alloc: " << e.what() << endl;
    }

    return 0;
}
13
Evan Gertis

Vous devez mettre vos exceptions en ordre inverse, en ce qui concerne leur relation d'héritage. std :: exception est la classe parente de std :: bad_alloc , c'est pourquoi elle se trouve auparavant dans la liste des captures. Donc, vous devez transformer votre code pour être:

   try {
      goesWrong();
   }
   catch (bad_alloc &e)
   {
      cout << "Catching bad_alloc: " << e.what() << endl;
   }
   catch (exception &e)
   {
      cout << "Catching exception: " << e.what() << endl;
   }

Vous n'êtes pas limité à catch objects: vous pouvez lancer des entiers, des caractères ... peu importe. Dans ce cas, catch(...) est le seul moyen sûr de toutes les attraper. 

Cela dit, il est conseillé d’utiliser des objets de la bibliothèque de classes standard. Et dans ce cas, puisque std :: exception est la classe de base pour toutes les exceptions (standard), il interceptera toutes les exceptions possibles levées.

Vous pouvez créer vos propres classes d'exception en les dérivant de std :: exception ou de std :: runtime_error , par exemple, de mon choix personnel.

J'espère que cela t'aides.

23
Baltasarq

En C++, l'ordre dans lequel les gestionnaires d'exceptions sont répertoriés est pris en compte lors de la mise en correspondance des gestionnaires avec les exceptions. Le premier gestionnaire capable de gérer l'exception sera appelé, même s'il existe une meilleure correspondance plus loin dans la liste. Ceci est différent de Java ou C #, où seule la meilleure correspondance sera appelée (et le compilateur vous oblige à la placer en haut de la liste).

Comme l’exception est transmise par référence, le polymorphisme s’applique; Cela signifie qu'une sous-classe peut être transmise à un gestionnaire qui attend sa classe parente. Puisque std :: bad_alloc est une sous-classe de std :: exception , il sera géré par le premier bloc catch.

Pour obtenir le comportement que vous attendiez, posez les blocs d'arrêt dans le sens inverse:

catch (bad_alloc &e)
{
   cout << "Catching bad_alloc: " << e.what() << endl;
}
catch (exception &e)
{
   cout << "Catching exception: " << e.what() << endl;
}

De cette manière, std :: bad_alloc correspondra au premier gestionnaire, tandis que std :: exception et toutes ses autres sous-classes correspondra au second.

0
James Raynard