====== Partie II – Vérifier que les exceptions sont bien capturées.======
[[in204:tds:sujets:td7|TD7]]
L'objet des questions suivantes est de pouvoir vérifier au moment de la compilation que les exceptions sont bien capturées ou bien que seules les exceptions indiquées sont supposées être déclencheés (cf. [[in204:cpp:syntax:exceptions:contract|les annotations relatives aux exceptions]]).
===== Question n°1 =====
L’exception ''division_by_zero'' peut être levée par la fonction ''divide''. Ajouter cette information à la fonction ''divide''.
Nous considérons que l'exception ''division_by_zero'' n'est plus capturée par la fonction ''divide'' et est propagée aux fonctions appelantes.
Dans ce cas nous devons indiquer que la fonction ''divide'' peut générer une exception. Nous avons plusieurs possibilités pour le faire.
* Indiquer que la fonction ''divide'' genére une exception de type ''division_by_zero''.\\
double divide(double, double) throw(division_by_zero);
* Indiquer que la fonction ''divide'' genére une exception sans spécifier laquelle. Dans ce cas, les syntaxes suivantes sont équivalentes\\
double divide(double, double) noexcept(false);
double divide(double, double) throw(...);
Ceci nous donne en conséquence les codes suivants pour la méthode ''divide'' :
double divide(double theNumerator, double theDivisor) throw(division_by_zero)
{
if(theDivisor == 0)
throw division_by_zero();
return theNumerator / theDivisor;
}
Jusqu'à la version C++14, nombreux étaient les compilateur qui considérait que :
double divide(double, double) throw(division_by_zero);
était equivalent à :
double divide(double, double) noexcept(false);
En fait les compilateur ne vérifiaient pas la nature des exceptions qui étaient capturées. De ce fait, depuis C++17, cette fonctionnalité a été déclarée comme "abandonnées" et désormais il est demandé de déclarer une fonction qui ne lève pas d'exception par : ''noexcept'' ou par ''noexcept(true)'' et une foncion qui lève une exception par soit ''noexcept(false)'' ou ''throw(...')''.
===== Question n°2 =====
Exécutez votre programme.
Comme l'exception n'est jamais capturée, celle-ci appelle le handler par défaut std::terminate qui termine le programme.
===== Question n°3 =====
Ajoutez les informations complémentaires à votre programme pour éviter ce comportement.
Pour la méthode ''test_divide'', nous devons
- indiquer qu'elle ne génère pas d'exceptions. En conséquence, nous devons lui ajouter un des marquages suivants :
void test_divide() noexcept;
void test_divide() noexcept(true);
void test_divide() throw(); // Attention, n'est plus supporté depuis la version C++17.
Si nous exécutons le code, l'exception n'est pas générée. Et le code s'exécute comme si cette exception n'avait pas existée.
===== Question n°4 =====
Complétez les informations pour que la fonction ''test_divide'' capture effectivement l'exception.
Ce qui donne pour cette fonction le code suivant :
void test_divide() noexcept
{
double i, j;
for(;;) {
std::cout << "Le numerateur (0 pour arreter): ";
std::cin >> i;
if(i == 0)
break;
std::cout << " Le denominateur : ";
std::cin >> j;
try
{
std::cout << "Resultat: " << divide(i,j) << std::endl;
}
catch(division_by_zero anException)
{
std::cout << "Erreur: " << anException.what() << std::endl;
}
}
}
Nous pouvons désormais marquer la fonction ''main'' comme étant une fonction ne génèrant aucune exception.
void main() noexcept
{
///
}
et nous obtiendrons une compilation garantissant que toutes les exceptions sont bien capturées.