User Tools

Site Tools


in204:tds:sujets:td6:part4

This is an old revision of the document!


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)

TD6

En C# (et aussi en java), vous avez la possibilité d’écrire un bloc finally.

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.
}

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 ?

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
}

Correction

Correction

Il est nécessaire que le code qui doit être exécuté soit appellé dans chacune des clauses catch et avant toute nouvelle propagation d'exception.

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 ?

Correction

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 :

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

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,

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.

class finally
{
  public :
    finally(){}
    ~finally() {}}

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.

in204/tds/sujets/td6/part4.1572783201.txt.gz · Last modified: 2019/11/03 12:13 by bmonsuez