Partage
  • Partager sur Facebook
  • Partager sur Twitter

Iterator custom

Sujet résolu
    2 juillet 2020 à 18:14:22

    Bonjour à tous,

    Je souhaite exposé des itérateurs customs pour la classe suivante :

    #ifndef MODEL_H
    #define MODEL_H
    
    #include <string>
    #include <vector>
    #include <memory>
    #include "account.h"
    
    class Model
    {
        struct InternalAccount
        {
            InternalAccount(Account const& acc, size_t id):
                account{ acc },
                id{ id }
            {
            }
    
            Account account;
            const size_t id;
        };
    
    public:
        
        //...
    
    private:
    
        std::vector<std::unique_ptr<InternalAccount>> accounts;
    
    };
    
    #endif // MODEL_H
    



    De façon a donner accès aux "internalAccount", en cachant le fait que ça soit des unique_ptr

    J'ai donc quelque chose comme ça :

    #ifndef MODEL_H
    #define MODEL_H
    
    #include <string>
    #include <vector>
    #include <memory>
    #include "account.h"
    
    class Model
    {
    
    public:
        class iterator{
        public:
            using difference_type = InternalAccount;
            using value_type = InternalAccount;
            using pointer = InternalAccount*;
            using reference = InternalAccount&;
            using iterator_category = std::forward_iterator_tag;
    
            iterator(pointer ptr);
            iterator& operator++();
            iterator operator++(int);
            bool operator==(iterator const& other) const;
            bool operator!=(iterator const& other) const;
    
            reference operator*();
            pointer operator->();
    
        private:
            pointer ptr;
        };
    
        class const_iterator{
        public:
            using difference_type = InternalAccount;
            using value_type = const InternalAccount;
            using pointer = InternalAccount*;
            using reference = InternalAccount&;
            using iterator_category = std::forward_iterator_tag;
    
            const_iterator(pointer ptr);
            const_iterator& operator++();
            const_iterator operator++(int);
            bool operator==(const_iterator const& other) const;
            bool operator!=(const_iterator const& other) const;
    
            const reference operator*();
            const pointer operator->();
    
        private:
            pointer ptr;
        };
    
        iterator begin();
        iterator end();
    
        const_iterator cbegin() const;
        const_iterator cend() const;
    };
    
    #endif // MODEL_H
    
    

    Avec les définitions suivante :

    Model::iterator Model::begin()
    {
        return iterator(accounts.begin()->get());
    }
    
    Model::iterator Model::end()
    {
         return iterator(std::begin(accounts)->get() + accounts.size());
    }
    
    Model::const_iterator Model::cbegin() const
    {
        return const_iterator(std::begin(accounts)->get());
    }
    
    Model::const_iterator Model::cend() const
    {
        return const_iterator(std::begin(accounts)->get() + accounts.size());
    }
    
    void Model::addAccount(const Model::InternalAccount &account)
    {
        accounts.push_back(std::make_unique<InternalAccount>(account));
    }
    
    Model::iterator::iterator(Model::iterator::pointer ptr) :
        ptr(ptr)
    {
    }
    
    Model::iterator &Model::iterator::operator++()
    {
        ptr++;
        return *this;
    }
    
    Model::iterator Model::iterator::operator++(int)
    {
        iterator i{ ptr };
        ptr++;
    
        return i;
    }
    
    bool Model::iterator::operator==(Model::iterator const& other) const
    {
        return (ptr == other.ptr);
    }
    
    bool Model::iterator::operator!=(Model::iterator const& other) const
    {
        return (ptr != other.ptr);
    }
    
    Model::iterator::reference Model::iterator::operator*()
    {
        return *ptr;
    }
    
    Model::iterator::pointer Model::iterator::operator->()
    {
        return ptr;
    }
    
    
    Model::const_iterator::const_iterator(Model::const_iterator::pointer ptr):
        ptr(ptr)
    {
    }
    
    Model::const_iterator &Model::const_iterator::operator++()
    {
        ptr++;
        return *this;
    }
    
    Model::const_iterator Model::const_iterator::operator++(int)
    {
        const_iterator i{ ptr };
        ptr++;
    
        return i;
    }
    
    bool Model::const_iterator::operator==(const Model::const_iterator &other) const
    {
        return (ptr == other.ptr);
    }
    
    bool Model::const_iterator::operator!=(const Model::const_iterator &other) const
    {
        return (ptr != other.ptr);
    }
    
    const Model::const_iterator::reference Model::const_iterator::operator*()
    {
         return *ptr;
    }
    
    const Model::const_iterator::pointer Model::const_iterator::operator->()
    {
        return ptr;
    }

    Sauf que j'ai un problème, l'accès aux éléments ne marche pas, j'ai des valeurs incohérentes au delà du premier élément, et ça peu finir sur un appel de "abort()" (sur Qt creator)

    J'avoue avoir un peu de mal a vraiment comprendre que doit renvoyer mon iterateur avec les différent opérateur (les const pour le const_iterator sur les operateur "*" et "->" par exemple sont noter sans effet pas Qt creator, mais je ne vois pas que faire d'autre), c'est donc un cumul d'observation et de deductions, avec une grande chance que beaucoup de choses soit fausses

    J'aimerais donc savoir ce que j'ai fais de mal avec mes iterateurs, c'est la première fois que je tente quelque chose comme ça, et j'ai un peu galerer a trouver des exemples qui correspondent a peu pres a ma situations (et qui n'heritent pas de std::iterator)

    Merci de votre lecture/aide

    -
    Edité par K4kugen 2 juillet 2020 à 18:24:21

    • Partager sur Facebook
    • Partager sur Twitter
      2 juillet 2020 à 18:48:13

      std::begin(accounts)-&gt;get() retourne le pointeur référencé par l'itérateur, ce n'est pas un itérateur, tu ne peux pas faire ++ptr dessus. Tes itérateurs custom ne devraient pas itérer sur un pointeur, mais sur std::vector::<std::unique_ptr<InternalAccount>>::iterator/const_iterator.

      • Partager sur Facebook
      • Partager sur Twitter
        2 juillet 2020 à 21:58:36

        Merci beaucoup, c'est en effet beaucoup plus logique, et ca marche beaucoup mieux x)

        Du coup ça devient :

         class iterator{
            public:
                using difference_type = InternalAccount;
                using value_type = InternalAccount;
                using pointer = InternalAccount*;
                using reference = InternalAccount&;
                using iterator_category = std::forward_iterator_tag;
        
                iterator(std::vector<std::unique_ptr<InternalAccount>>::iterator it);
                iterator& operator++();
                iterator operator++(int);
                bool operator==(iterator const& other) const;
                bool operator!=(iterator const& other) const;
        
                reference operator*();
                pointer operator->();
        
            private:
                 std::vector<std::unique_ptr<InternalAccount>>::iterator it;
            };
        
            class const_iterator{
            public:
                using difference_type = InternalAccount;
                using value_type = const InternalAccount;
                using pointer = InternalAccount*;
                using reference = InternalAccount&;
                using iterator_category = std::forward_iterator_tag;
        
                const_iterator(std::vector<std::unique_ptr<InternalAccount>>::const_iterator it);
                const_iterator& operator++();
                const_iterator operator++(int);
                bool operator==(const_iterator const& other) const;
                bool operator!=(const_iterator const& other) const;
        
                const reference operator*();
                const pointer operator->();
        
            private:
                 std::vector<std::unique_ptr<InternalAccount>>::const_iterator it;
            };

        Avec :

        Model::iterator::reference Model::iterator::operator*()
        {
            return *it->get();
        }
        
        Model::iterator::pointer Model::iterator::operator->()
        {
            return it->get();
        }
        
        //...
        
        const Model::const_iterator::reference Model::const_iterator::operator*()
        {
             return *it->get();
        }
        
        const Model::const_iterator::pointer Model::const_iterator::operator->()
        {
            return it->get();
        }

        Encore merci à toi

        • Partager sur Facebook
        • Partager sur Twitter

        Iterator custom

        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
        • Editeur
        • Markdown