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 :

Définir son propre reverse_iterator à partir d'un pointeur nu


Sujet :

C++

  1. #1
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut Définir son propre reverse_iterator à partir d'un pointeur nu
    Bonjour,

    je souhaite définir un reverse_iterator pour l'une des mes classes mais je ne vois pas trop comment le faire de manière simple, c'est-à-dire sans créer d'objet supplémentaire.
    Concrètement, je dispose d'une classe avec un pointeur nu pour laquelle j'ai déjà défini un itérateur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Foo
    {
    public:
      typedef int * iterator;
      iterator begin() { return m_data; }
      iterator end() { return m_data + m_size; }
    private:
      size_t m_size;
      iterator m_data;
    };
    Pour définir un reverse_iterator, j'ai besoin de définir des fonctions rbegin et rend, mais j'ai également besoin de pouvoir parcourir mes données en sens inverse avec une surcharge de l'opérateur++, de manière à pouvoir écrire ce genre de boucle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Foo bar;
    for(Foo::reverse_iterator data = bar.rbegin() ; data != bar.rend() ; ++data)
    { /* instructions */; }
    Existe-t-il un moyen simple de définir un tel itérateur à partir d'un pointeur nu?

  2. #2
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2014
    Messages
    345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2014
    Messages : 345
    Points : 1 211
    Points
    1 211
    Par défaut
    Bonjour,

    Non, car cela impliquerait que tu redéfinisses l'opérateur ++ de int, ce qui n'est pas possible.
    Par contre tu peux boucler à l'envers :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for (Foo::iterator it = bar.end(); it != bar.begin(); --it)
      // EDIT: à oublier, non fonctionnel


    Edit: C'est faux voir les messages suivants.

    La solution la plus propre étant tout de même d'implémenter une vraie classe reverse_iterator.

  3. #3
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Ne peut-on pas utiliser directement std::reverse_iterator<>?

    Si je comprends bien la doc, il doit être possible d'implémenter rbegin() en termes de:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    reverse_iterator<Foo::iterator> rbegin() {
    	return reverse_iterator<Foo::iterator>(end());
    }
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  4. #4
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonjour The Hound,

    merci pour ta réponse.

    N'est-il pas possible d'utiliser la classe reverse_iterator de a STL par exemple?

    J'avais pensé à l'exemple que tu donnes mais je pense qu'il y a un bogue car la condition
    empêche d'atteindre le premier élément de bar.
    Si je ne me trompe pas, il faudrait quand même définir des fonctions rbegin et rend (c'est peut-être faux, je n'ai pas essayé) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    iterator rbegin() { return bar.begin() - 1; }
    iterator rend() { return bar.end() - 1; }
    pour pouvoir écrire des boucles du type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Foo::iterator it = bar.rend() ; it != bar.rbegin() ; --it)
    Du coup, je trouve un peu dommage de ne pas avoir de reverse_iterator.

  5. #5
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonjour Medinoc,

    merci pour ta réponse.

    Citation Envoyé par Médinoc Voir le message
    Ne peut-on pas utiliser directement std::reverse_iterator<>?

    Si je comprends bien la doc, il doit être possible d'implémenter rbegin() en termes de:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    reverse_iterator<Foo::iterator> rbegin() {
    	return reverse_iterator<Foo::iterator>(end());
    }
    J'essaye de ce pas et je fais un retour ici.

  6. #6
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    "Tout simplement" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // g++ -Wall -Wextra -Wconversion -Wsign-conversion -std=c++11 -pedantic -fopenmp main.cpp -o main && ./main
     
    #include <iostream>
    #include <vector>
     
     
    int main (void)
    {
    	std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
     
    	using rit_t = std::reverse_iterator<int *>;
     
    	for (auto rit = rit_t(v.data() + v.size()); rit != rit_t(v.data()); ++rit)
    	{
    		std::cout << *rit << " ";
    	}
    	std::cout << std::endl;
     
    	return 0;
    }
    Sortie :

  7. #7
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2014
    Messages
    345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2014
    Messages : 345
    Points : 1 211
    Points
    1 211
    Par défaut
    Je t'ai répondu en prenant en compte le fait que tu ne voulais pas impliquer une autre classe.
    Si tu peux utiliser un reverse_iterator, de la STL en plus, fais-le.

    Dans la boucle que je t'ai donné, --it (pré-décrémentation) et il me semble que la condition est évaluée, puis it est décrémenté, et ensuite le bloc for est exécuté (quelqu'un pour confirmer ?). Si je dis vrai, il en résulte que tous tes éléments sont parcourus, y compris le premier.

    Edit: c'est faux

  8. #8
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonjour,

    je confirme que la solution proposée par Medinoc fonctionne parfaitement! Merci!

    Pour résumer, voici une exemple très synthétique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    #include <iterator>
    template<class T> class Foo
    {
    public:
     
      typedef T * iterator;
      typedef std::reverse_iterator<iterator> reverse_iterator;
     
    public:
     
      Foo(size_t size)
      :m_size(size), m_data(new T[m_size])
      {}
     
      ~Foo()
      { delete [] m_data; }
     
      iterator begin() 
      { return m_data; }
     
      iterator end()
      { return m_data + m_size; }
     
      reverse_iterator rbegin()
      { return std::reverse_iterator<iterator>( this->end() ); }
     
      reverse_iterator rend()
      { return std::reverse_iterator<iterator>( this->begin() ); }
     
    private:
     
      size_t m_size;
      iterator m_data;
    };

  9. #9
    Membre éclairé
    Inscrit en
    Décembre 2010
    Messages
    290
    Détails du profil
    Informations forums :
    Inscription : Décembre 2010
    Messages : 290
    Points : 719
    Points
    719
    Par défaut
    Citation Envoyé par the Hound Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for (Foo::iterator it = bar.end(); it != bar.begin(); --it)
      // ...
    Ouch ouch ... Si je suis bien reveillé, "it" va pointer, lors du premier passage dans la boucle, sur le premier élément APRES la fin de la collection, donc à un emplacement invalide.
    De plus, il s'arrêtera lorsqu'il atteint le premier élément, sans passer par celui-ci.
    Je me trompe quelque part ?

  10. #10
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Citation Envoyé par the Hound Voir le message
    Je t'ai répondu en prenant en compte le fait que tu ne voulais pas impliquer une autre classe.
    Si tu peux utiliser un reverse_iterator, de la STL en plus, fais-le.

    Dans la boucle que je t'ai donné, --it (pré-décrémentation) et il me semble que la condition est évaluée, puis it est décrémenté, et ensuite le bloc for est exécuté (quelqu'un pour confirmer ?). Si je dis vrai, il en résulte que tous tes éléments sont parcourus, y compris le premier.
    Je viens de vérifier et ça ne fonctionne définitivement pas.
    Il y a une seconde erreur dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Foo::iterator it = bar.end();
    puisque la fonction bar.end() ne pointe pas sur le dernier élément.

    La version correcte est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for ( Foo::iterator it = bar.end()-1 ; it != bar.begin()-1 ; --it )
      // ...

  11. #11
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Citation Envoyé par phi1981 Voir le message
    Ouch ouch ... Si je suis bien reveillé, "it" va pointer, lors du premier passage dans la boucle, sur le premier élément APRES la fin de la collection, donc à un emplacement invalide.
    De plus, il s'arrêtera lorsqu'il atteint le premier élément, sans passer par celui-ci.
    Je me trompe quelque part ?
    Oui, oui, c'est bien ça, bien vu!

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

Discussions similaires

  1. [ODS] Définir son propre style (via template) à l'aide d'ODS listing
    Par joyeux_lapin13 dans le forum ODS et reporting
    Réponses: 3
    Dernier message: 19/10/2011, 11h49
  2. Réponses: 6
    Dernier message: 06/07/2007, 11h44
  3. Réponses: 15
    Dernier message: 04/01/2007, 11h15
  4. [win32] définir son propre DLLMAIN.
    Par FamiDoo dans le forum MFC
    Réponses: 3
    Dernier message: 24/07/2006, 16h01
  5. [Hibernate] Définir son propre id generator
    Par K-Kaï dans le forum Hibernate
    Réponses: 6
    Dernier message: 23/05/2006, 13h03

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