Forum Programmation.c++ conteneur en retour de fonction

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
2
30
déc.
2021

bonjour,
je ne suis plus novice en c++, et pourtant j'en apprends chaque jour.
Je viens de tomber sur une erreur sympa, qui après avoir été isolée, s'est avérée quelque peu incompréhensible.
peut-on retourner un conteneur depuis une fonction getConteneur?
Voici mon exemple:

    class Foo{
        public:
            Foo(){
                i.push_back(1);
                i.push_back(2);
                i.push_back(3);
            }

            std::vector<int> getvect()
            {
                return i;
            }

        private:
            std::vector<int> i;
    };


    int main(int argc, char** argv)
    {
        Foo a;
        for(auto it = a.getvect().begin(); it != a.getvect().end(); it++)
            std::cout << (*it);
        return EXIT_SUCCESS;
    }

Est-ce quelqu'un pourrait m'expliquer à quoi rime le résultat?
merci!!!!

  • # Retourner une copie ou une référence ?

    Posté par  . Évalué à 6. Dernière modification le 30 décembre 2021 à 20:56.

    Salut,
    Alors je ne suis pas expert mais je dirais que le problème vient du fait que getvect renvoie une copie du vector de Foo. Dans la déclaration de la boucle la fonction getvect est appelé et renvoie alors un nouveau vector, la fonction begin est alors appelé sur celui-ci puis le vector nouvellement crée est détruit et l'itérateur est sauvegardé dans la variable it, sauf que le conteneur étant détruit it pointe sur une zone mémoire au contenu disons aléatoire.

    Pour que cela fonctionne il faudrait renvoyer une référence sur le vector, donc:

                std::vector<int>& getvect()
                {
                    return i;
                }
  • # que devrait retourner au getter?

    Posté par  . Évalué à 6.

    Bonjour,

    Que doit retourner un getter? Est-ce une copie de ce qui est dans l'objet ou est-ce un moyen d'accéder à ce qui est dans l'objet? Tu as choisi de retourner une copie, pourquoi pas.

    Maintenant tu appelles 2 fois la fonction getvect(), elle te retourne donc à chaque fois une copie. Et bien évidemment tu ne peux pas aller du début d'une copie à la fin d'une autre copie! Quand tu appelles 2 fois une fonction comme tu l'as fait, tu peux t'attendre ne pas toujours avoir le même résultat. Il faudrait donc écrire:

            auto vect = a.getvect();
            for ( auto it = vect.begin(); it != vect.end(); it++ )
                std::cout << *it;

    ou plus simplement:

            for ( auto item : a.getvect() )
                std::cout << item;

    Mais le plus souvent on préfère que le getter retourne une référence constante à ce qui est dans l'objet. En écrivant:

                std::vector<int>const& getvect()const
                {
                    return i;
                }

    on donne la possibilité à celui qui appelle getvect() d'utiliser directement la donnée incluse ou bien d'en faire une copie. Alors mes 2 exemples et ton code fonctionnent. L'inconvénient de cette méthode est que ce qui est retourné est non modifiable. Mais c'est plutôt un avantage, c'est quand même dangereux de permettre à une entité externe d'agir sur des données interne à ton objet.

    Le moyen de donner cet accès en modification, c'est le code que t'as indiqué @Dareg. Mais c'est plutôt à éviter.

  • # Plus simple...

    Posté par  (site web personnel) . Évalué à 3.

    Moi j’aurais fais ça comme ceci ↓

    #include <vector>
    #include <iostream>
    
    class A
    {
        public :
            A()
            : v({1, 2, 3})
            {;}
    
            auto const & getvect() const
            { return v; }
    
        private :
            std::vector<int> v;
    };
    
    int main()
    {
        using namespace std;
        A a;
    
        for( auto & i : a.getvect() )
            cout << i;
    
        cout << endl;
    }
    • [^] # Re: Plus simple...

      Posté par  . Évalué à 3.

      perso j'aurai pas mis le auto en retour de getVect() car j'aime bien avoir une interface claire, et pas "devine mon retour" pour le lecteur; le fait que getVect() te renvoie un vector<int> est lié à sa conception interne et ne fait pas partie de l'interface.

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

      • [^] # Re: Plus simple...

        Posté par  (site web personnel) . Évalué à 3. Dernière modification le 05 janvier 2022 à 19:09.

        En effet. Je trouvais intéressant de montrer à quoi auto peut également servir :)

        Sinon, je me dis que std::vector est peut-être un type qui pourrait changer dans le future. Donc en pratique, personnellement je passe par un alias, genre

        class A
        {
            public :
                typedef std::vector<int> TVect;
        
                A()
                : v({1, 2, 3})
                {;}
        
                TVect const & getvect() const
                { return v; }
        
            private :
                TVect v;
        };

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.