User Tools

Site Tools


in204:tds:sujets:td6:part2

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
in204:tds:sujets:td6:part2 [2020/11/01 10:50]
bmonsuez
in204:tds:sujets:td6:part2 [2022/11/18 10:49] (current)
Line 1: Line 1:
-====== Partie II – Vérifier que les exceptions sont bien capturées.======+====== Partie II – Spécialisation par contraintes ​======
  
 [[in204:​tds:​sujets:​td6|TD6]] [[in204:​tds:​sujets:​td6|TD6]]
  
 +===== Question n°1 =====
  
-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]]).+Nous considérons toujours notre code affichant le contenu d'un conteneur tel que défini dans la [[in204:tds:sujets:td6:part1|première partie]].
  
-===== Question n°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) 
 +
 +    aStream << "​{";​ 
 +    auto end aContainer.end();​ 
 +    for(auto it aContainer.begin();​ it !end;) 
 +    { 
 +        aStream << *it ++; 
 +        if(it !end) 
 +            aStream << ", "; 
 +    } 
 +    aStream << "​}";​ 
 +}  
 +</​code>​
  
-L’exception ''​division_by_zero''​ peut être levée ​par la fonction ​''​divide''​. Ajouter cette information à la fonction ''​divide''​. ​+==== Question n°1.1 ===== 
 + 
 +Déterminer ce qui va caractériser un conteneur pouvant ​être pris comme argument ​par la fonction ​précédente ?
  
 <hidden Correction>​ <hidden Correction>​
  
 +En fait, il est attendu que le conteneur fournisse deux méthodes :
  
-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.+  * `begin()`: retournant un itérateur marquant le début de la séquence,​ 
 +  * `end()`: retournant un itérateur marquant le fin de la séquence.
  
-Dans ce cas nous devons indiquer que la fonction ​''​divide''​ peut générer une exception. Nous avons plusieurs possibilités pour le faire.+L'itérateur qui est retourné doit supporter : 
 +  * l'accès en lecture des données stockées dans le conteneur,​ 
 +  * le parcours en avant.
  
-  * Indiquer que la fonction ​''​divide''​ genére une exception ​de type ''​division_by_zero''​.\\ <code cpp> +Il n'a pas besoin ​de supporter le multipasse.
-double divide(double,​ double) throw(division_by_zero);​ +
-</​code>​+
  
-  * Indiquer que la fonction ''​divide''​ genére une exception sans spécifier laquelle. Dans ce cas, les syntaxes suivantes sont équivalentes\\ <code cpp> +</hidden>
-double divide(double,​ double) noexcept(false);​ +
-double divide(double,​ double) throw(...);​ +
-</code>+
  
  
-Ceci nous donne en conséquence les codes suivants pour la méthode ''​divide''​ :+==== Question n°1.2 =====
  
 +Implanter un concept qui permet de formaliser les exigences que vous venez de formuler ?
 +
 +<hidden Correction>​
 <code cpp> <code cpp>
-double divide(double theNumerator,​ double theDivisor) throw(division_by_zero)+template<​typename T> 
 +concept Browsable = requires ​(const T& a)
 { {
-    ​if(theDivisor == 0+    ​{ a.begin() } -> std::​forward_iterator;​ 
-        throw division_by_zero()+    { a.end() } -> std::​forward_iterator
-    return theNumerator / theDivisor+};
-}+
 </​code>​ </​code>​
- 
- 
-Jusqu'​à la version C++14, nombreux étaient les compilateur qui considérait que : 
-<code cpp> 
-double divide(double,​ double) throw(division_by_zero);​ 
-</​code>​ 
-était equivalent à : 
-<code cpp> 
-double divide(double,​ double) noexcept(false);​ 
-</​code>​ 
-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(...'​)''​. 
  
 </​hidden>​ </​hidden>​
  
 +==== Question n°1.3 =====
  
-===== Question n°2 =====  +Ajouter les contraintes à l'​opérateur %%<<​%% qui a été défini pour un conteineur.
- +
-Exécutez votre programme.+
  
 <hidden Correction>​ <hidden Correction>​
- +<code cpp> 
- +template<​typename containerT, typename charT, typename traits = std::​char_traits<​charT>>​ 
-Comme l'​exception n'est jamais capturéecelle-ci appelle le handler par défaut ​std::terminate qui termine le programme+requires Browsable<​containerT>​ 
 +std::​basic_ostream<​charTtraits>&​ 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 << "​}";​ 
 +    return aStream; 
 + 
 +</​code>​
 </​hidden>​ </​hidden>​
-===== Question n°3 =====  
  
-Ajoutez les informations complémentaires à votre programme pour éviter ce comportement. 
  
-<hidden Correction>​+==== Question n°1.4 =====
  
 +Introduisez une implantation de l'​opérateur `<<` qui pour tout type affiche '​NONE'​.
  
-Pour la méthode ''​test_divide'',​ nous devons ​ +<hidden Correction>​ 
- +<code cpp> 
-  - indiquer qu'​elle ne génère pas d'​exceptions. En conséquencenous devons lui ajouter un des marquages suivants ​: +template<​typename Ttypename charT, typename traits = std::​char_traits<charT>
-<code cpp>  +std::​basic_ostream<​charT,​ traits>&​ operator << ​(std::​basic_ostream<​charT,​ traits>&​ aStream, const T& aContainer
-void test_divide() noexcept; +
-void test_divide() noexcept(true)+    std::cout << "​NONE"​
-void test_divide() throw()// Attention, n'est plus supporté depuis la version C++17.+    ​return aStream; 
 +}
 </​code>​ </​code>​
- 
-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. 
- 
 </​hidden>​ </​hidden>​
  
-===== Question n°4 =====  
  
-Complétez les informations pour que la fonction ''​test_divide''​ capture effectivement l'​exception.+===== Question n°2 ====
  
-<​hidden>​+Nous avons deux fonctions pour effectuer un tri, l'​algorithme simple de tri que nous avons implanté et l'​algorithme ``std::​sort`` fourni par la STL. 
  
 +Cependant notre algorithme fonctionne pour des itérateurs qui ne supportent pas l'​accès indexé tandis que l'​algorithme ``std::​sort`` est un quicksort et nécessite un accès indexé mais qui est plus rapide.
  
-Ce qui donne pour cette fonction ​le code suivant ​:+Modifier ​le code de ``std::​simple_sort`` pour appeller ``std::​sort`` si jamais les itérateurs sont des itérateurs supportant l'​accès direct (``std::random_access_iterator``).
  
 +<hidden Correction>​
 <code cpp> <code cpp>
-void test_divide() noexcept+template<​typename ​ iterator>​ 
 +void simple_sort(iterator start, iterator end)  
 +    requires(std::​forward_iterator<​iterator>​ && ! std::​random_access_iterator<​iterator>​ && std::​input_or_output_iterator<​iterator>​)
 { {
-  double i, j; +    ​std::cout << "Insertion Sort\n"; 
-  for(;;) { +    ​for(;start !end; start ++)
-    ​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;+        ​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); 
 +        }
     }     }
-    catch(division_by_zero anException+
-    { +template<​typename iterator>​ 
-        std::cout << "Erreur: ​" ​<< anException.what() << ​std::endl; +void simple_sort(iterator start, iterator end)  
-    } +    ​requires(std::​random_access_iterator<​iterator>​ && std::​input_or_output_iterator<​iterator>​) 
-  } +
 +    std::cout << "Quicksort\n"
 +    return ​std::sort(start, end);
 } }
 </​code>​ </​code>​
  
-Nous pouvons désormais marquer la fonction ''​main''​ comme étant une fonction ne génèrant aucune exception. ​+Et nous exécutons le code suivant :
  
 <code cpp> <code cpp>
-void main() noexcept 
 { {
-/// +    std::​list<​int>​ l = {1, 7, 3, 4, 9, 2, 5}; 
-}+    std::​vector<​int>​ v(l.begin(),​ l.end()); 
 +    simple_sort(l.begin(),​ l.end()); 
 +    std::cout << l << std::​endl;​ 
 +    simple_sort(v.begin(),​ v.end()); 
 +    std::cout << v << std::​endl;​ 
 +</code> 
 +  
 +qui génèrera la sortie suivante: 
 +<​code>​ 
 +Insertion Sort 
 +{1, 2, 3, 4, 5, 7, 9} 
 +Quicksort 
 +{1, 2, 3, 4, 5, 7, 9}
 </​code>​ </​code>​
  
-et nous obtiendrons une compilation garantissant que toutes les exceptions sont bien capturées.+</​hidden>​
  
- 
-</​hidden>​ 
  
in204/tds/sujets/td6/part2.1604227806.txt.gz · Last modified: 2020/11/01 10:50 by bmonsuez