IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Pourquoi utiliser un iterator sur des containers ?


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Février 2007
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 206
    Points : 79
    Points
    79
    Par défaut Pourquoi utiliser un iterator sur des containers ?
    Salut à tous, je me pose une petite question depuis quelques temps, pourquoi utiliser des iterators pour itérer sur des containers ?

    Admettons qu'on ait ce vector:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    vector<int> myvector;
    myvector.resize(10);
    fill (myvector.begin(),myvector.end(),5);
    Pour itérer je fais toujours ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for(int i = 0; i < (int) myvector.size(); i++) {
        cout << myvector.at(i) << endl;
    }
    En quoi est-ce mieux de faire ça ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      for (vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
        cout << " " << *it;
    Je trouve ça beaucoup plus contraignant à écrire ^^

    Pouvez-vous m'éclairer ? Merci d'avance

  2. #2
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 159
    Points
    3 159
    Par défaut
    Salut

    Dans ton exemple ça a l'air plus contraignant, parce que tu n'utilises qu'une seule fois "it", mais si tu l'utilises plusieurs fois, comme quelques dizaines de fois ? De plus, tu dis que ça paraît contraignant car ton for est "lourd", mais tu peux l'alléger avec un typedef sur" vector<int>::iterator" par exemple.

    L'avantage de l'itérateur est que son fonctionnement est unifié entre différents containers, mais aussi que tu t'abstrais de la structure en tableau. En utilisant l'indice, tu utilises malgré toi une information structurelle supplémentaire.

    Enfin, je pense qu'il doit aussi y avoir une histoire de perfo, mais je vais laisser les vrais spécialistes répondre.

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Février 2007
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 206
    Points : 79
    Points
    79
    Par défaut
    Ok, merci du renseignement =)

    Il doit me manquer certaines notions, car dans certains cas je n'arrive pas à utiliser d'iterator.
    Par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template<typename T>
    static void display(vector<T> myVector) {
        vector<T>::const_iterator it; // ne compile pas
        for(it = myVector.begin(); it != myVector.end(); it++)
    	cout << *it << endl;
    }
    Je suis obligé d'utiliser:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template<typename T>
    static void display(vector<T> myVector) {
    	try {
    	for(int i = 0; i < (int) myVector.size(); i++)
    		cout << myVector.at(i) << endl;
    	} catch(exception &e) {
    		cout << "you didn't pass a valid vector in parameter" << endl;
    		cout << e.what() << endl;
    	}
    }
    J'ai essayé de faire comme dans cet exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <typename T>
    void ecrire(const std::vector<int> & v){
    	typename std::vector<T>::const_iterator vit(v.begin(),vend(v.end());
    	for(;vit!=vend;++vit) std::cout << *vit << ' ';
    }
    Mais mon compilateur me dit qu'il ne connaît pas la méthode "vend"

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Salut,

    Effectivement, l'énorme avantage des itérateurs est qu'ils présentent une interface unifiée, quelle que soit la collection réellement utilisée.

    L'opérateur [] n'est en effet utilisable que pour le std::vector (et pour la std::map, que j'ai en horreur, à cause de son mode de fonctionnement )

    Par contre, le problème auquel tu es confronté avec le code que tu présente:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template<typename T>
    static void display(vector<T> myVector) {
        vector<T>::const_iterator it; // ne compile pas
        for(it = myVector.begin(); it != myVector.end(); it++)
    	cout << *it << endl;
    }
    c'est que tu travailles avec une fonction template.

    Le fait est que le langage n'arrive pas à déduire le type de std::vector<T>::const_iterator.

    Pour résoudre ce problème, il faut "simplement" préciser que tu sais que std::vector<T>::const_iterator représente bel et bien un type, et que le compilateur peut donc te faire confiance.

    Il "suffit" donc de modifier la fonction pour qu'elle prenne la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template<typename T>
    static void display(vector<T> myVector) {
        typename vector<T>::const_iterator it; // ne compile pas
        for(it = myVector.begin(); it != myVector.end(); it++)
    	cout << *it << endl;
    }
    C'est fou, comme la présence d'un seul mot peut changer les choses, non ?

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Février 2007
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 206
    Points : 79
    Points
    79
    Par défaut
    Merci de ta réponse

    Pour le code, le typename signifie au compilateur qu'il doit me faire confiance ?

    Ou il ya autre chose que je ne vois pas ?^^

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Citation Envoyé par scheme Voir le message
    Merci de ta réponse

    Pour le code, le typename signifie au compilateur qu'il doit me faire confiance ?

    Ou il ya autre chose que je ne vois pas ?^^
    C'est à vrai dire un peu plus complexe que cela, et je l'avais dit plus par "joke".

    En fait, il faut, effectivement, préciser que const_iterator est un type qui est déclaré dans la classe std::vector (dans ton exemple).

    Et c'est le rôle du mot clé typename

    Mais, si tu veux savoir quelles sont les raisons pour lesquelles la présence de ce mot clé est nécessaire à cet endroit, il faudra attendre un peu

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Février 2007
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 206
    Points : 79
    Points
    79
    Par défaut
    Ok, merci de ces précisions

    En fait le typename définit un type, donc it sera bien de type vector<T>::const_iterator, et T sera remplacé à l'éxécution

    Je suis presque fier d'avoir compris^^

    Merci à vous de m'avoir donné vos précieux conseils

  8. #8
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 159
    Points
    3 159
    Par défaut
    Il me paraît utile de dire simplement que le mot clé typename sert à lever une ambiguité. En effet, si tu lis ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    vector<T>::const_iterator
    const_iterator peut être un type mais aussi un membre statiques de la classe vector<T>. En ajoutant typename, tu dis au compilo "t'inquiète mon pote, c'est bien un type et non un membre". En revanche, tu ne définis pas le type, c'est bien vector<T> qui le définit.

    Voir ici.

  9. #9
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Les itérateurs permettent comme cela été dit une approche + générique. Et même on peut carrément penser en terme de Range (couple it début/it fin).

    En reprenant ta fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<typename iterator_t_>
    static void display(iterator_t_ debut_, iterator_t_ fin_) {
        for(; debut_ != fin_; ++debut_)
        cout << *it << endl;
    }
    fonctionne pour autre chose que des vecteurs.

    Et en allant plus loin pas besoin de display car la STL propose des iterateurs pour les flux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::copy(my_bag.begin(),my_bag.end(),std::ostream_iterator<TYPE>(std::cout,"\n"));

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 8
    Dernier message: 13/11/2008, 22h28
  2. Réponses: 16
    Dernier message: 12/11/2008, 21h36
  3. utilisations de pointeurs sur des objets
    Par niarkyzator dans le forum Delphi
    Réponses: 21
    Dernier message: 13/12/2006, 10h42
  4. Utilisation de SUM() sur des 'real'
    Par f.le.chat dans le forum MS SQL Server
    Réponses: 6
    Dernier message: 30/06/2006, 16h16
  5. [RegEx] utilisation de preg_replace sur des balises
    Par Kerod dans le forum Langage
    Réponses: 5
    Dernier message: 09/12/2005, 14h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo