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:45] bmonsuez [Question n°1.3] |
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 ===== |
+ | |||
+ | Déterminer quel type d'itérateur est requis pour effectuer les opérations ? | ||
+ | |||
+ | <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. | ||
+ | |||
+ | 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> | ||
+ | <code cpp> | ||
+ | template<typename iterator> | ||
+ | void simple_sort(iterator start, iterator end) | ||
+ | requires(std::forward_iterator<iterator> && std::input_or_output_iterator<iterator>) | ||
{ | { | ||
- | test_divide() ; | + | 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> | ||
+ | </hidden> | ||
- | ==== Question n°1.2 ==== | ||
- | Procéder à une exécution et regarder ce qui se passe quand une division par 2 se produit. | + | ==== Question n°1.3 ==== |
- | ==== Question n°1.3 ==== | + | Nous souhaitons ajouter l'opérateur suivant qui liste l'ensemble des éléments d'un conteneur: |
- | Exécuter en mode débogage et placer un point d’arrêt sur le code de capture de l’exception. | + | <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> | ||
- | <hidden Correction> | + | 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 : |
- | 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é). | + | <code cpp> |
- | * [[https://code.visualstudio.com/docs/cpp/cpp-debug|Debug C++ in Visual Studio Code]] | + | #include<list> |
+ | #include"simple_sort.hpp" | ||
- | * [[http://wiki.codeblocks.org/index.php/Debugging_with_Code::Blocks|Debugging with Code::Blocks]] | + | 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://docs.microsoft.com/fr-fr/visualstudio/debugger/quickstart-debug-with-cplusplus?view=vs-2019|Quickstart: Debug with C++ using the Visual Studio debugger]] | ||
- | * [[https://medium.com/yay-its-erica/xcode-debugging-with-breakpoints-for-beginners-5b0d0a39d711|Xcode Debugging with Breakpoints (for Beginners)]] | + | ==== Question n°1.4 ==== |
- | * [[https://www.cs.swarthmore.edu/~newhall/unixhelp/howto_gdb.php|gdb (and ddd) Guide]] | + | 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 : |
- | * [[https://www.emacswiki.org/emacs/DebuggingWithEmacs|Debugging with Emacs]] | + | <code cpp> |
+ | #include<list> | ||
+ | #include"sort.hpp" | ||
- | </hidden> | + | struct Toto {}; |
- | ===== Question n°2 : Création d’une classe d’exception ===== | + | 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> | ||
- | 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>]]. | + | Expliquer pourquoi le compilateur génére une erreur ? |
- | Cette classe devra s’appeler ''division_by_zero''. | + | <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 : | ||
- | ==== Question n°2.1 ==== | + | <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> | ||
- | 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. | + | 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`. |
- | Penser à fournir un message d’erreur cohérent. | + | </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]] |