This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
in204:tds:sujets:td6:part4 [2019/11/03 12:16] bmonsuez [Question n°1] |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | |||
- | ====== Partie IV – S’assurer qu’un code soit toujours effectué, qu’une exception se produise ou ne se produise pas ====== | ||
- | |||
- | **(A faire en dehors du TD)** | ||
- | |||
- | [[in204:tds:sujets:td6|TD6]] | ||
- | |||
- | |||
- | En C# (et aussi en java), vous avez la possibilité d’écrire un bloc finally. | ||
- | <code csharp> | ||
- | try | ||
- | { | ||
- | … | ||
- | } | ||
- | finally | ||
- | { | ||
- | // Ce code est toujours exécuté | ||
- | // Qu’une exception se produise | ||
- | // Que cette exception soit capturée | ||
- | // Que cette exception ne soit pas capturée | ||
- | // Qu’une exception soit générée dans le traitement | ||
- | // de l’exception. | ||
- | // Qu’aucune exception ne se produise. | ||
- | } | ||
- | </code> | ||
- | |||
- | Le code qui se trouve dans le bloc du finally est toujours exécuté, qu’une exception se produise ou qu’aucune exception ne se produise. | ||
- | |||
- | ===== Question n°1 ===== | ||
- | |||
- | En C++, cette construction n’existe pas. Est-ce qu’il est possible de garantir la même chose en C++ en utilisant des blocs catch ? | ||
- | |||
- | <code cpp> | ||
- | try | ||
- | { | ||
- | … | ||
- | } | ||
- | catch(type1 e) | ||
- | { | ||
- | // Capture les exceptions dérivant de type1 | ||
- | } | ||
- | catch(type1 e) | ||
- | { | ||
- | // Capture les exceptions dérivant de type2 si elles n’ont pas été capturées | ||
- | // par les exceptions de type1. | ||
- | } | ||
- | catch(…) | ||
- | { | ||
- | // Capture toutes les exceptions n’ayant pas été capturées par une clause | ||
- | // précédente | ||
- | } | ||
- | </code> | ||
- | |||
- | <hidden Correction> | ||
- | |||
- | Nous avons deux cas à traiter, soit une exception est propagée, soit aucune exception n'est propagée. Dans ce cas, nous devons avoir pour la fonction la structure suivante : | ||
- | |||
- | <code cpp> | ||
- | return_type function(...) | ||
- | { | ||
- | return_type value; | ||
- | try | ||
- | { | ||
- | // Code du corps de la fonction. | ||
- | // Il n'est pas possibile d'utiliser l'instruction ''return''. | ||
- | } | ||
- | catch(...) | ||
- | { | ||
- | // Code à exécuter à la fin de la fonction | ||
- | throw; | ||
- | // Réamorce l'exception capturée. | ||
- | } | ||
- | // Code à exécuter à la fin de la fonction | ||
- | return value; | ||
- | } | ||
- | </code> | ||
- | |||
- | </hidden> | ||
- | |||
- | ===== Question n°2 ===== | ||
- | |||
- | Nous souhaitons que la fonction ''divide'' définie à la question précédente affiche le message « fonction terminée » à la fin de la fonction et même si une exception a été levée. | ||
- | |||
- | Comment faire avec la solution proposée à la question précédente ? | ||
- | |||
- | Quel est le défaut de cette approche ? | ||
- | |||
- | <hidden Correction> | ||
- | |||
- | Pour la fonction ''divide'' qui peut générer une fonction, nous allons devoir gérer les deux cas de figure, le premier cas où la fonction génère une exception, le second cas où la fonction ne génère pas d'exception. Ce qui nous donne le cas de figure suivant : | ||
- | |||
- | <code cpp> | ||
- | double divide(double theNumerator, double theDivisor) | ||
- | throw(division_by_zero) | ||
- | { | ||
- | double result; | ||
- | try | ||
- | { | ||
- | if (theDivisor == 0) | ||
- | throw division_by_zero(); | ||
- | result = theNumerator / theDivisor; | ||
- | } | ||
- | catch(...) | ||
- | { | ||
- | std::cout << "Fonction terminée" << std::endl; | ||
- | throw; | ||
- | } | ||
- | std::cout << "Fonction terminée" << std::endl; | ||
- | return result; | ||
- | } | ||
- | </code> | ||
- | |||
- | Cette approche n'est pas satisfaisante pour les raisons suivantes : | ||
- | * la duplication de code, nous devons dupliquer au moins deux fois le code indiquant s'exécutant à la fin de la fonction (ceci peut-être compensé par un appel à une fonction qui factorise le code devant être exécuté en fin de la fonction). | ||
- | * la nécessité de devoir stocker le résultat pour pouvoir ensuite le retourner après avoir exécuter le code de fin | ||
- | * l'impossibilité d'avoir des points de sortie (''return'') multiples. Ceci peut-être compensé par des ''goto'' à une section finale correspondant à la fin de la fonction, | ||
- | |||
- | </hidden> | ||
- | ===== Question n°3 ===== | ||
- | |||
- | Nous suggérons de contourner la difficulté en utilisant un objet. Nous savons qu’un objet alloué sur la pile est systématiquement détruit lorsqu’il sort du bloc d’activation. | ||
- | Lorsqu’un objet est détruit, son destructeur est appelé. | ||
- | |||
- | Remarque : Dans le destructeur, il est possible de faire exécuter le code qui aurait été mis dans le bloc finally de C# ou de JAVA et que nous souhaitons systématiquement voir exécuté. | ||
- | Compléter la classe suivante pour qu’elle affiche le message « fonction terminée » lorsque l’objet est détruit. | ||
- | |||
- | <code cpp> | ||
- | class finally | ||
- | { | ||
- | public : | ||
- | finally(){} | ||
- | ~finally() {…} | ||
- | … | ||
- | } | ||
- | </code> | ||
- | |||
- | ===== Question n°3 ===== | ||
- | |||
- | Mettez en œuvre cette solution en lieu et place de la solution proposée à la question 1.2. | ||
- | |||
- | Vérifiez que cette solution fonctionne correctement. | ||
- | |||
- | |||