User Tools

Site Tools


in204:tds:sujets:td4:part1

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:td4:part1 [2019/10/15 09:29]
bmonsuez [Question n°1.2]
in204:tds:sujets:td4:part1 [2022/11/18 10:49] (current)
Line 90: Line 90:
 </​code>​ </​code>​
 <hidden Explication & correction>​ <hidden Explication & correction>​
 +
  
 <code cpp> <code cpp>
Line 107: Line 108:
         const Allocator&​ alloc = Allocator() );         const Allocator&​ alloc = Allocator() );
 </​code>​ </​code>​
-</​hidden>​ 
  
 Le compilateur identifie ''​int[]''​ comme étant un ''​int*''​ qui se respecte les exigences définies par  [[https://​en.cppreference.com/​w/​cpp/​named_req/​InputIterator|input iterator]]. Comme le tableau contient 8 éléments, ''​myints+8''​ définit un pointeur qui pointe sur l'​élément qui se trouverait à l'​indice ''​8'',​ soit ''​myints[8]''​. Cependant, cet élément n'​existe pas ! C'est bien un élément situé après le dernier élément dans le tableau ''​myints''​ qui est ''​myints[8]''​ et qui est référencé par le pointeur ''​myints+7''​. En conséquence,​ ''​myints+8''​ marque bien la fin de la séquence, puisque c'est l'​itérateur qui suit le dernier itérateur valide de la séquence. Le compilateur identifie ''​int[]''​ comme étant un ''​int*''​ qui se respecte les exigences définies par  [[https://​en.cppreference.com/​w/​cpp/​named_req/​InputIterator|input iterator]]. Comme le tableau contient 8 éléments, ''​myints+8''​ définit un pointeur qui pointe sur l'​élément qui se trouverait à l'​indice ''​8'',​ soit ''​myints[8]''​. Cependant, cet élément n'​existe pas ! C'est bien un élément situé après le dernier élément dans le tableau ''​myints''​ qui est ''​myints[8]''​ et qui est référencé par le pointeur ''​myints+7''​. En conséquence,​ ''​myints+8''​ marque bien la fin de la séquence, puisque c'est l'​itérateur qui suit le dernier itérateur valide de la séquence.
Line 126: Line 126:
 </​code>​ </​code>​
  
-à l'​exception que l'​itérateur ''​up'​ ayant pour type ''​std::​vector<​int>::​iterator''​ doit supporter l'​opération ''​-''​ dite différence de position. Cette opération n'est pas disponible pour tous les types d'​itérateurs . Elle n'est en fait que disponible pour les itérateurs qui respectent les exigences définies par [[https://​en.cppreference.com/​w/​cpp/​named_req/​RandomAccessIterator|random access iterator]], ce qui est le cas pour l'​itérateur de ''​std::​vector<​int>::​iterator''​ défini dans [[https://​en.cppreference.com/​w/​cpp/​container/​vector|std::​vector]].+à l'​exception que l'​itérateur ''​up'' ayant pour type ''​std::​vector<​int>::​iterator''​ doit supporter l'​opération ''​-''​ dite différence de position. Cette opération n'est pas disponible pour tous les types d'​itérateurs . Elle n'est en fait que disponible pour les itérateurs qui respectent les exigences définies par [[https://​en.cppreference.com/​w/​cpp/​named_req/​RandomAccessIterator|random access iterator]], ce qui est le cas pour l'​itérateur de ''​std::​vector<​int>::​iterator''​ défini dans [[https://​en.cppreference.com/​w/​cpp/​container/​vector|std::​vector]].
  
 Si nous souhaitons utiliser un autre containeur comme par exemple le containeur [[https://​en.cppreference.com/​w/​cpp/​container/​set|std::​set]],​ nous pouvons écrire le code suivant : Si nous souhaitons utiliser un autre containeur comme par exemple le containeur [[https://​en.cppreference.com/​w/​cpp/​container/​set|std::​set]],​ nous pouvons écrire le code suivant :
Line 157: Line 157:
 </​code>​ </​code>​
  
 +En fait, cette boucle peut-être effectuée par un appel à la fonction ​ [[https://​en.cppreference.com/​w/​cpp/​iterator/​distance|std::​distance]] définie dans le fichie d'​entête [[https://​en.cppreference.com/​w/​cpp/​header/​algorithm|<​algorithm>​]],​ ce qui réduit le code précédent à :
 +<code cpp>
 + std::​set<​int>​ intSet(v.begin(),​ v.end());
 + auto upSet = upper(intSet.begin(),​ intSet.end(),​ 20);
 +        std::cout << "First value greater than 20  at position "
 +                  << std::​distance(v.begin(),​ upSet) << std::endl;
 +</​code>​
 +
 +L'​intérêt de faire appel à la fonction [[https://​en.cppreference.com/​w/​cpp/​iterator/​distance|std::​distance]] qui a pour protopye : 
 +<code cpp>
 +template<​class inputIterator>​
 +typename std::​iterator_traits<​inputIterator>::​difference_type
 +    distance(inputIterator first, inputIterator last);
 +</code
 +est de laisser le compilateur sélectonner l'​algorithme le plus efficace pour calculer le nombre d'​itérations nécessaires pour aller du premier itérateur ''​first''​ au second itérateur ''​last''​. Si les itérateurs sont des itérateurs respectant les exigences relatives à un [[https://​en.cppreference.com/​w/​cpp/​named_req/​RandomAccessIterator|random access iterator]], dans ce cas, le code exécuté sera équivalent à :
 +<code cpp>
 +    return last - first;
 +</​code>​
 +
 +Par contre si l'​itérateur n'est pas un [[https://​en.cppreference.com/​w/​cpp/​named_req/​RandomAccessIterator|random access iterator]], l'​itérateur est supposé être un [[https://​en.cppreference.com/​w/​cpp/​named_req/​InputIterator|input iterator]] et en conséquence le code exécuté est similaire au suivant :
 +
 +<code cpp>
 +    std::​iterator_traits<​inputIterator>::​difference_type position = 0; //upSet - v.begin()
 +    for(auto it = intSet.begin();​ it != upSet; it++) { position ++; }
 +    return position.
 +</​code>​
 +
 +En fait, la classe [[https://​en.cppreference.com/​w/​cpp/​iterator/​iterator_traits|std::​iterator_traits]] permet d'​accéder plus simplement et de manière homogène aux champs des itérateurs ou des éléments assimilés à des itérateurs comme les pointeurs. Cette classe expose plusieurs définitions de type et notamment la définition de type qui s'​avère être ''​iterator_category''​ qui identifie le type de l'​itérateur.
 +
 +Ainsi le code de la fonction ''​std::​distance''​ devient :
 +
 +<code cpp>
 +
 +namespace {    ​
 +    template<​class inputIterator,​ class iteratorTag>​
 +    typename std::​iterator_traits<​inputIterator>::​difference_type
 +        distance(inputIterator first, inputIterator last, iteratorTag)
 +    {
 +        std::​iterator_traits<​inputIterator>::​difference_type position = 0; //upSet - v.begin()
 +        for(auto it = intSet.begin();​ it != upSet; it++) { position ++; }
 +        return position.
 +    }
 +    template<​class inputIterator>​
 +    typename std::​iterator_traits<​inputIterator>::​difference_type
 +        distance(inputIterator first, inputIterator last, std::​random_access_iterator_tag)
 +    {
 +        return last - first;
 +    }
 +}
 +
 +template<​class inputIterator>​
 +typename std::​iterator_traits<​inputIterator>::​difference_type
 +    distance(inputIterator first, inputIterator last)
 +{
 +    return distance(first,​ last, 
 +        std::​iterator_traits<​inputIterator>::​iterator_category());​
 +}
 +
 +</​code>​
 +
 +Quand on appelle la fonction ''​distance'',​ elle appelle la fonction distance qui prend trois arguments, le dernier étant un objet ayant un type identifiant le type d'​itérateur. Deux fonctions ''​distances''​ internes (ie. dans un espace de nom anoyme) sont définies: ​
 +  * <code cpp>
 +    template<​class inputIterator,​ class iteratorTag>​
 +    typename std::​iterator_traits<​inputIterator>::​difference_type
 +        distance(inputIterator first, inputIterator last, iteratorTag)
 +</​code>​Cette fonction est la fonction générique qui fonctionne pour l'​intégralité des différents type d'​itérateurs ''​iteratorTag''​.
 +  * <code cpp>
 +    template<​class inputIterator>​
 +    typename std::​iterator_traits<​inputIterator>::​difference_type
 +        distance(inputIterator first, inputIterator last, std::​random_access_iterator_tag)
 +</​code>​Cette fonction est la version spécialisée pour le type ''​iteratorTag''​ qui doit être égal à [[https://​en.cppreference.com/​w/​cpp/​iterator/​iterator_tags|std::​random_access_iterator_tag]].
 + 
 +Comme la version spécialisée est prioritaire sur la version générique,​ si l'​itérateur définit ''​iterator_category''​ comme étant [[https://​en.cppreference.com/​w/​cpp/​iterator/​iterator_tags|std::​random_access_iterator_tag]],​ c'est la version spécialisée de la fonction qui sera appelé, sinon la version générique,​ ce qui permet d'​avoir recours à la méthode optimale pour calculer la distance.
 +
 +</​hidden>​
  
 ===== Question n°2 ===== ===== Question n°2 =====
Line 214: Line 289:
 using namespace std; using namespace std;
  
-int testSortAndUpper()+void testSortAndUpper()
 { {
 +    std::​vector<​int>​ v{ 10, 20, 30, 30, 20, 10, 10, 20 };
     // Appel de la fonction "​upper'​ sur le vecteur en commençant par le premier élément ​     // Appel de la fonction "​upper'​ sur le vecteur en commençant par le premier élément ​
     // et en terminant avec le dernier.     // et en terminant avec le dernier.
Line 231: Line 307:
  
  
-int testSortHeapAndUpper()+void testSortHeapAndUpper()
 { {
 +    std::​vector<​int>​ v{ 10, 20, 30, 30, 20, 10, 10, 20 };
 +    std::​make_heap(v.begin(),​ v.end());
     // Appel de la fonction "​upper'​ sur le vecteur en commençant par le premier élément ​     // Appel de la fonction "​upper'​ sur le vecteur en commençant par le premier élément ​
     // et en terminant avec le dernier.     // et en terminant avec le dernier.
in204/tds/sujets/td4/part1.1571131782.txt.gz · Last modified: 2019/10/15 09:29 by bmonsuez