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

Langage C++ Discussion :

Getter renvoyant un pointeur ?


Sujet :

Langage C++

  1. #1
    Membre éclairé
    Homme Profil pro
    Doctorant en Astrophysique
    Inscrit en
    Mars 2009
    Messages
    312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Astrophysique
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2009
    Messages : 312
    Par défaut Getter renvoyant un pointeur ?
    Bonjour.

    J'ai encore un peu de mal avec la gestion de la mémoire au sein du C++, et j'aurai une question spécifique.

    Voilà un résumé du problème :
    J'ai une structure listElement qui rassemble pas mal de données (dont des QPixmap (je bosse avec Qt)).
    J'ai une classe ListClass qui contient un std::vector<listElement> _listvector qui rassemble plus de 300 éléments. Cette classe permet d'initialiser tous ces éléments mais également d'effectuer certaines opérations dessus.

    Ce que j'aimerai dans la mesure du possible c'est initialiser une variable de type ListClass au lancement de mon programme et qu'ensuite toutes les autres classes lancées pendant l'exécution du programme aient directement accès aux éléments du std::vector<listElement> (en "lecture seule"). Le problème actuellement c'est que si je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    inline listElement ListClass::getElement(int i) const 
    { 
         return _listVector[i];
    }
    ça effectue une copie inutile, et ça prend vite de la place en mémoire (surtout avec les images).

    Quelle serait la meilleure solution pour parvenir à ce dont j'ai envie ?

    Merci beaucoup .

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 634
    Par défaut
    Salut,

    Tu pourrais tout simplement envisager de renvoyer... une référence constante
    Une autre solution serait peut-être (si tu dois régulièrement parcourir ta liste depuis l'extérieur de la classe) de prévoir une fonction begin() et une fonction end(), renvoyant toutes deux des iterateurs, respectivement sur ... le premier élément de la liste et sur... ce qui suit le dernier (l'équivalent de la_liste.begin() et la_liste.end() )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre éclairé
    Homme Profil pro
    Doctorant en Astrophysique
    Inscrit en
    Mars 2009
    Messages
    312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Astrophysique
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2009
    Messages : 312
    Par défaut
    Merci pour ta réponse.

    Concernant le renvoie de la référence constante, ça consisterai à ça ? :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    inline const listElement& ListClass::getElement(int i) const 
    { 
         return _listvector[i];
    }
    (puisque l'opérateur [] renvoie en principe une ref constante ?)

    Je rajoute quelques précisions :
    le std::vector<listElement> est un élément private de la classe (puisque je veux que seule la classe puisse le modifier). En revanche j'aimerai bien que les éléments contenus dans le std::vector<listElement> soient accessibles directement (en lecture seule) de n'importe quelle partie du programme sans passer par des copies (car les listElement sont lourds en mémoire).

    Ah oui, dernière demande : j'ai actuellement des fonctions qui effectuent des recherches et renvoient les éléments correspondants du type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    inline listElement ListClass::getElementName(const std::string &name) const 
    { 
         listElement output=_listvector[0];
         for(unsigned int i=0;i<_listvector.size();i++)
              if(_listvector[i].name==name)
                    output=_listvector[i];
         return output;
    }
    Comment faire de même mais en renvoyant une référence constante ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 634
    Par défaut
    Citation Envoyé par Kaluza Voir le message
    Merci pour ta réponse.

    Concernant le renvoie de la référence constante, ça consisterai à ça ? :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    inline const listElement& ListClass::getElement(int i) const 
    { 
         return _listvector[i];
    }
    Oui, pour autant que _listvector contienne... des listElements et non des pointeurs sur listElement
    (puisque l'opérateur [] renvoie en principe une ref constante ?)
    Pas tout à fait...

    L'opérateur [] est généralement défini de deux manières:
    Il renvoie une référence non constante lorsque tu l'appelle depuis un objet non constant et une référence constante quand tu l'appelle depuis un objet constant

    Mais si tu invoque cet opérateur depuis une fonction constante, c'est effectivement la version constante de l'opérateur qui sera appelée, et tu obtiendra donc... une référence constante.

    Je rajoute quelques précisions :
    le std::vector<listElement> est un élément
    private de la classe (puisque je veux que seule la classe puisse le modifier). En revanche j'aimerai bien que les éléments contenus dans le std::vector<listElement> soient accessibles directement (en lecture seule) de n'importe quelle partie du programme sans passer par des copies (car les listElement sont lourds en mémoire).
    C'est la raison pour laquelle je te conseille de créer deux fonctions (begin et end)...

    La première renvoie un itérateur constant sur le premier élément de _listvector et la seconde renvoie un itérateur constant sur... ce qui suit le dernier élément de _listvector:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    const_itertator ListClass::begin() const
    {
        return _listvector.begin();
    }
    const_iterator ListClass::end() const
    {
        return _listvector.end();
    }
    avec, dans la définition de ta classe, un typedef publique proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef std::vector<listElement>::const_iterator const_iterator;
    Tu pourra alors envisager de travailler sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int main()
    {
        ListClass truc;
        /* on rempli truc */
        for(ListClass::const_iterator it=truc.begin(); it!=truc.end();++it)
        {
            /* utilisation de it pour accéder à chaque élément */
        }
    }
    Tu pourrais d'ailleurs envisager la création de foncteurs proches de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct Foncteur
    {
        void operator()(listElement const & le)
        {
            /* ce qu'il faut faire */
        }
    }
    et l'utilisation de std::for_each (en C++1x) ou de boost::for_each(si tu ne dispose pas d'un compilateur supportant la nouvelle norme):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main()
    {
        ListClass truc;
        /*remplir truc */
        std::for_each(truc.begin(),truc.end(),Foncteur());
    }
    Ah oui, dernière demande : j'ai actuellement des fonctions qui effectuent des recherches et renvoient les éléments correspondants du type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    inline listElement ListClass::getElementName(const std::string &name) const 
    { 
         listElement output=_listvector[0];
         for(unsigned int i=0;i<_listvector.size();i++)
              if(_listvector[i].name==name)
                    output=_listvector[i];
         return output;
    }
    Comment faire de même mais en renvoyant une référence constante ?
    Simplement en... renvoyant une référence constante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    inline listElement const & ListClass::getElementName(const std::string &name) const 
    { 
         listElement output=_listvector[0];
         for(unsigned int i=0;i<_listvector.size();i++)
              if(_listvector[i].name==name)
                    output=_listvector[i];
         return output;
    }
    Nota: typiquement, ce genre de fonction n'a pas vraiment d'intérêt à être inlinée... mais bon, ce n'est qu'un détail
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre éprouvé Avatar de nowahn
    Homme Profil pro
    Inscrit en
    Août 2008
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 84
    Par défaut
    Salut,

    Citation Envoyé par koala01
    Simplement en... renvoyant une référence constante
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    inline listElement const & ListClass::getElementName(const std::string &name) const 
    { 
         listElement output=_listvector[0];
         for(unsigned int i=0;i<_listvector.size();i++)
              if(_listvector[i].name==name)
                    output=_listvector[i];
         return output;
    }
    Euh, on peut renvoyer une référence constante à une variable locale ? (peut être mais je sais plus.)

    Quoi qu’il en soit, ce code occasionne toujours des copies de listElement (output=...). Je passerais par des itérateurs pour réaliser l’opération sans copie :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    inline listElement const & ListClass::getElementName(const std::string &name) const 
    {
         typedef std::vector<listElement>::const_iterator CI;
         CI output=_listvector.begin();
         for(CI Iter=_listvector.begin();Iter!=_listvector.end();++Iter)
              if(Iter->name==name)
                   output=Iter;
         return *output;
    }

    Edit:
    PS : ton algorithme est bizarre, il sert à renvoyer une référence vers le derniér élément dont name est le name recherché ?
    Si c’est bien le cas, il vaut mieux rechercher le premier à partir de la fin :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    inline listElement const & ListClass::getElementName(const std::string &name) const 
    {
         typedef std::vector<listElement>::const_reverse_iterator CI;
         for(CI Iter=_listvector.rbegin();Iter!=_listvector.rend();++Iter)
              if(Iter->name==name)
                   return *Iter;
         return _listvector.front();
    }
    ou plus simple encore, utiliser std::find()

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 634
    Par défaut
    Citation Envoyé par nowahn Voir le message
    Salut,


    Euh, on peut renvoyer une référence constante à une variable locale ? (peut être mais je sais plus.)
    Effectivement, non... je devais être vachement fatigué

    Par contre, tu peux renvoyer une référence sur un membre de l'objet et même la référence sur un élément renvoyée par un membre de l'objet...

    Quoi qu’il en soit, ce code occasionne toujours des copies de listElement (output=...). Je passerais par des itérateurs pour réaliser l’opération sans copie :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    inline listElement const & ListClass::getElementName(const std::string &name) const 
    {
         typedef std::vector<listElement>::const_iterator CI;
         CI output=_listvector.begin();
         for(CI Iter=_listvector.begin();Iter!=_listvector.end();++Iter)
              if(Iter->name==name)
                   output=Iter;
         return *output;
    }

    Edit:
    PS : ton algorithme est bizarre, il sert à renvoyer une référence vers le derniér élément dont name est le name recherché ?
    Si c’est bien le cas, il vaut mieux rechercher le premier à partir de la fin :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    inline listElement const & ListClass::getElementName(const std::string &name) const 
    {
         typedef std::vector<listElement>::const_reverse_iterator CI;
         for(CI Iter=_listvector.rbegin();Iter!=_listvector.rend();++Iter)
              if(Iter->name==name)
                   return *Iter;
         return _listvector.front();
    }
    Effectivement, c'est ce que je voulais proposer en tant solution

    Je l'ai dit, je devais être 'achement fatigué
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Getter, renvoyer une référence ou une copie ?
    Par the_angel dans le forum C++/CLI
    Réponses: 6
    Dernier message: 13/04/2012, 12h41
  2. Réponses: 10
    Dernier message: 29/05/2011, 19h18
  3. Renvoyer un pointeur avec un cast ?
    Par tintin72 dans le forum C
    Réponses: 8
    Dernier message: 19/05/2008, 18h08
  4. Renvoyer un pointeur de type structure
    Par bluecurve dans le forum C
    Réponses: 2
    Dernier message: 18/05/2007, 20h29
  5. Renvoyer des pointeurs pour du c.
    Par lolobubu40 dans le forum C++
    Réponses: 2
    Dernier message: 19/07/2006, 18h49

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