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:part1 [2019/11/03 10:47] bmonsuez [Question n°1.2] |
in204:tds:sujets:td6:part1 [2022/11/18 10:49] (current) |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Partie I – Manipulation des Exceptions====== | + | ====== Partie I – Définitions des exigences ====== |
[[in204:tds:sujets:td6|TD6]] | [[in204:tds:sujets:td6|TD6]] | ||
- | ===== Question n°1 : Gestion simple des exceptions en C++ ===== | ||
- | ==== Question n°1.1 ==== | + | ===== Question n°1===== |
- | Implanter le code suivant dans un nouveau projet. | + | Créer un projet dans lequel vous intégrez le fichier "simple_sort.hpp" qui contient la fonction de comparaison suivante: |
<code cpp> | <code cpp> | ||
+ | #pragma once | ||
+ | #include<algorithm> | ||
- | #include <iostream> | + | template<typename iterator> |
- | + | void simple_sort(iterator start, iterator end) | |
- | double divide(double a, double b); | + | |
- | void test_divide(); | + | |
- | + | ||
- | void test_divide() | + | |
{ | { | ||
- | double i, j; | + | for(;start != end; start ++) |
- | for(;;) { | + | { |
- | std::cout << "Le numerateur (0 pour arreter): "; | + | auto it = start; it++; |
- | std::cin >> i; | + | for(;it != end; it ++) |
- | if(i == 0) | + | { |
- | break; | + | // Compare si les deux elements sont dans le bon ordre. |
- | std::cout << " Le denominateur : "; | + | if (*start > *it) |
- | std::cin >> j; | + | std::swap(*start, *it); |
- | std::cout << "Resultat: " << divide(i,j) << std::endl; | + | } |
- | } | + | } |
} | } | ||
+ | </code> | ||
- | double divide(double a, double b) | ||
- | { | ||
- | try { | ||
- | if(!b) throw b; | ||
- | } | ||
- | catch (double b) { | ||
- | std::cout << "Ne peut pas diviser par zero.\n"; | ||
- | return b; | ||
- | } | ||
- | return a/b; | ||
- | } | ||
- | void main() | + | ==== Question n°1.1 ===== |
- | { | + | |
- | test_divide() ; | + | |
- | } | + | |
- | </code> | + | Déterminer quel type d'itérateur est requis pour effectuer les opérations ? |
- | ==== Question n°1.2 ==== | + | <hidden Correction> |
+ | Il s'agit d'un itérateur: | ||
+ | |||
+ | * devant offrir une itération croissante, | ||
+ | * devant offrir la possibilité de reprendre l'itération à partir d'une position antérieurement stockée. | ||
- | Procéder à une exécution et regarder ce qui se passe quand une division par 0 se produit. | + | Si nous regardons les caractéristiques des itérateurs: [[https://en.cppreference.com/w/cpp/iterator|Iterator library]], nous constatons que: |
+ | |||
+ | * //LegacyInputIterator//: ne supporte pas plusieurs passes et ne supporte pas l'écriture, | ||
+ | * //LegacyForwardIterator//: supporte plusieurs passes mais ne supporte pas obligatoire l'écriture, | ||
+ | * //LegacyOuputIterator//: supporte l'écriture. | ||
+ | |||
+ | De fait, nous devons garantir à la fois la lecture et l'écriture, ce qui signifie que nous devons nous assurer que l'itérateur respect les contracts requis pour un //LegacyForwardIterator// et un //LegacyOuputIterator//. | ||
+ | |||
+ | </hidden> | ||
+ | |||
+ | |||
+ | ==== Question n°1.2 ===== | ||
+ | |||
+ | Ajouter une contrainte imposant que le type passé à la fonction correspond bien au type d'itérateur que vous avez identifié. | ||
<hidden Correction> | <hidden Correction> | ||
- | Lors d'une division par zéro se produit, le code | ||
<code cpp> | <code cpp> | ||
- | std::cout << "Ne peut pas diviser par zero.\n"; | + | template<typename iterator> |
+ | void simple_sort(iterator start, iterator end) | ||
+ | requires(std::forward_iterator<iterator> && std::input_or_output_iterator<iterator>) | ||
+ | { | ||
+ | std::cout << "Insertion Sort\n"; | ||
+ | for(;start != end; start ++) | ||
+ | { | ||
+ | auto it = start; it++; | ||
+ | for(;it != end; it ++) | ||
+ | { | ||
+ | // Compare si les deux elements sont dans le bon ordre. | ||
+ | if (*start > *it) | ||
+ | std::swap(*start, *it); | ||
+ | } | ||
+ | } | ||
+ | } | ||
</code> | </code> | ||
- | est exécutée et la fonction retourne ''0''. Ceci signifie que l'exception de type ''double'' a été générée et a été capturée par la clause ''catch(double)''. | ||
</hidden> | </hidden> | ||
- | ==== Question n°1.3 ==== | ||
- | Exécuter en mode débogage et placer un point d’arrêt sur le code de capture de l’exception. | ||
- | <hidden Correction> | + | ==== Question n°1.3 ==== |
- | L'objectif de cette question est de vous faire manipuler vos outils pour utiliser l'environnement de dévogage de votre environnement de développement. Bien entendu, en fonction de votre environnement, vous avez des procédures différentes pour positionner un point d'arrêt. | + | |
- | Pour mémoire, voici quelques références pour placer des points d'arrêts sur les différents outils (sans garantie aucune d'exhaustivité). | + | Nous souhaitons ajouter l'opérateur suivant qui liste l'ensemble des éléments d'un conteneur: |
- | * [[https://code.visualstudio.com/docs/cpp/cpp-debug|Debug C++ in Visual Studio Code]] | + | <code cpp> |
+ | template<typename containerT, typename charT, typename traits = std::char_traits<charT>> | ||
+ | std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT, traits>& aStream, const containerT& aContainer) | ||
+ | { | ||
+ | aStream << "{"; | ||
+ | auto end = aContainer.end(); | ||
+ | for(auto it = aContainer.begin(); it != end;) | ||
+ | { | ||
+ | aStream << *it ++; | ||
+ | if(it != end) | ||
+ | aStream << ", "; | ||
+ | } | ||
+ | aStream << "}"; | ||
+ | } | ||
+ | </code> | ||
- | * [[http://wiki.codeblocks.org/index.php/Debugging_with_Code::Blocks|Debugging with Code::Blocks]] | + | Ajouter ce code à votre fichier 'simple_sort.hpp' et puis tester ensuite à la fois la précédente fonction et cette nouvelle fonction avec le code suivant : |
- | * [[https://docs.microsoft.com/fr-fr/visualstudio/debugger/quickstart-debug-with-cplusplus?view=vs-2019|Quickstart: Debug with C++ using the Visual Studio debugger]] | + | <code cpp> |
- | * [[https://medium.com/yay-its-erica/xcode-debugging-with-breakpoints-for-beginners-5b0d0a39d711|Xcode Debugging with Breakpoints (for Beginners)]] | + | #include<list> |
+ | #include"simple_sort.hpp" | ||
- | * [[https://www.cs.swarthmore.edu/~newhall/unixhelp/howto_gdb.php|gdb (and ddd) Guide]] | + | int main() |
+ | { | ||
+ | std::list<int> v = {1, 7, 3, 4, 9, 2, 5}; | ||
+ | simple_sort(v.begin(), v.end()); | ||
+ | std::cout << v; | ||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
- | * [[https://www.emacswiki.org/emacs/DebuggingWithEmacs|Debugging with Emacs]] | ||
- | </hidden> | + | ==== Question n°1.4 ==== |
- | ===== Question n°2 : Création d’une classe d’exception ===== | + | |
- | Nous envisageons désormais faire les choses correctement. Nous souhaitons définir une classe exception qui dérive de la classe [[https://en.cppreference.com/w/cpp/error/exception|std::exception]] se trouvant définie dans le fichier d'entête [[https://en.cppreference.com/w/cpp/header/exception|<exception>]]. | + | Dans la question précédente, nous avons défini une nouvelle surcharge de l'opérateur %%<<%%. En fait, cette surcharge n'est pas optimale, puisqu'il suffit que je définisse un type quelconque non supporté et cela ne fonctionne plus : |
- | Cette classe devra s’appeler ''division_by_zero''. | + | <code cpp> |
+ | #include<list> | ||
+ | #include"sort.hpp" | ||
- | ==== Question n°2.1 ==== | + | struct Toto {}; |
+ | int main() | ||
+ | { | ||
+ | std::list<int> v = {1, 7, 3, 4, 9, 2, 5}; | ||
+ | simple_sort(v.begin(), v.end()); | ||
+ | std::cout << v; | ||
+ | std::cout << Toto() << std::endl; | ||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
- | Créer la classe ''division_by_zero''. Elle pourra être définie dans un fichier d’entête ''math.hpp'' qui contiendra aussi l’entête de la fonction ''divide''. Le fichier associé ''math.cpp'' contiendre la code de la fonction divide. | + | Expliquer pourquoi le compilateur génére une erreur ? |
- | Penser à fournir un message d’erreur cohérent. | + | <hidden Correction> |
+ | En fait, il n'y a pas de surcharge de l'opérateur %%<<%% pour le type `Toto`, en conséquence, le compilateur va rechercher dans les opérateurs qui n'ont pas de contraintes sur les types, vous vous souvenez qu'on essaye d'abord les opérateurs les plus généraux et ensuite les moins généraux. Il trouve donc dans l'espace de nom courant l'opérateur : | ||
+ | |||
+ | <code cpp> | ||
+ | template<typename containerT, typename charT, typename traits = std::char_traits<charT>> | ||
+ | std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT, traits>& aStream, const containerT& aContainer) {...} | ||
+ | </code> | ||
+ | |||
+ | et ne sait pas que cet opérateur n'est définit que pour les objets qui sont des conteneurs au sens de la STL. En conséquence de quoi, il génère une erreur puisqu'il essaye d'instancier un code qui ne supporte pas des objets de type `Toto`. | ||
+ | |||
+ | </hidden> | ||
- | ==== Question n°2.2 ==== | ||
- | Modifier les fonctions ''divide'' et ''test_divide'' pour prendre ne plus lancer et capturer une exception de type ''double'' mais de type ''division_by_zero''. | + | [[in204:tds:sujets:td6:part2|Partie 2]] |