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 :

Comment stocker une copie locale dans un pointeur ?


Sujet :

C++

  1. #1
    Membre éprouvé

    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 448
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 448
    Points : 1 234
    Points
    1 234
    Par défaut Comment stocker une copie locale dans un pointeur ?
    Si j'écris ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        void addObject(myObject o, const int& i) {
            o.setI(i);
     
            this->myVector.push_back(&o);
        }
    je suppose que o (la copie locale) est détruit à la fin de la fonction.

    Donc comment est-ce que je peux conserver un pointeur dessus dans myVector de façon sûre ?
    Notez, que le fait que myVector stocke des pointeurs et non des objets n'est pas matière à débat.

  2. #2
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void addObject(myObject const& o, int /*const&*/ i) {
    	auto po = new myObject(o);
    	po->setI(i);
    	myVector.push_back(po);
    }
    ?

    Passer un int par ref constante est surprenant.

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 669
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 669
    Points : 10 674
    Points
    10 674
    Par défaut
    Tiens étonnant pour toi Iradrille de ne pas proposer les std::shared_ptr

  4. #4
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par foetus Voir le message
    Tiens étonnant pour toi Iradrille de ne pas proposer les std::shared_ptr
    Probablement un bon cas d'utilisation d'unique_ptr, mais "Notez, que le fait que myVector stocke des pointeurs et non des objets n'est pas matière à débat."

  5. #5
    Membre éprouvé

    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 448
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 448
    Points : 1 234
    Points
    1 234
    Par défaut
    [QUOTE=Iradrille;7833162]
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void addObject(myObject const& o, int /*const&*/ i) {
    	auto po = new myObject(o);
    	po->setI(i);
    	myVector.push_back(po);
    }
    Je suis selon toi, obligé de faire une copie de la copie locale (càd le paramètre o)?
    Ok, je comprends.

    Citation Envoyé par Iradrille Voir le message
    ?

    Passer un int par ref constante est surprenant.
    J'ai pas encore vraiment fait le point sur la façon dont il convient de passer les types de base en paramètre.

    Citation Envoyé par Iradrille Voir le message
    Probablement un bon cas d'utilisation d'unique_ptr, mais "Notez, que le fait que myVector stocke des pointeurs et non des objets n'est pas matière à débat."
    Un pointeur intelligent reste acceptable, ce n'était pas précisé

  6. #6
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par Sergejack Voir le message
    Je suis selon toi, obligé de faire une copie de la copie locale (càd le paramètre o) ?
    L'objet "o", est local, il est supprimé en sortant de la fonction. Si tu stockes un objet dans ton vecteur, tu en feras une copie, donc pas de problèmes.
    Ici tu stockes un pointeur, dès que tu sort de la fonction, le pointeur pointe sur un objet qui n'existe plus.

    Tu es donc obligé d'en faire une copie "persistante", en passant par un new.

    edit : ha bah tu as compris le problème pendant que je postais.

    Note tout de même que si tu ne cherches pas à en faire une copie, ceci est possible
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void addObject(myObject & o, int i) {
    	o.setI(i); // ce n'est à priori pas de rôle de addObject de modifier o (tu ne modifie plus une copie de o)
    	myVector.push_back(&o);
    }

  7. #7
    Membre éprouvé

    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 448
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 448
    Points : 1 234
    Points
    1 234
    Par défaut
    C'est quand même dommage de devoir passer par un constructeur de copie.
    J'avais espéré qu'il y avait une astuce pour éviter le coût d'une telle opération (si on retire le setI).

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 128
    Points : 33 052
    Points
    33 052
    Billets dans le blog
    4
    Par défaut
    Dommage ?
    Comment penses-tu faire autrement ?
    L'objet est détruit et tu veux le garder, la seule et unique solution est de le copier quelque part où tu peux le garder. Dans la heap avec new.

  9. #9
    Membre éprouvé

    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 448
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 448
    Points : 1 234
    Points
    1 234
    Par défaut
    Ben en fait dans du code qui existe, il y a des objets crées comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    if (actN > 0) {
        AccountRP lARP(actN);
        ... // du code à la pelle
    }
    et je voudrais que ça devienne.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    if (actN > 0) {
        AccountRP lARP(actN);
        ... // du code à la pelle
        myVector.push_back(&lARP);
    }
    sauf que je sais que c'est invalide en l'état et je trouverai dommage de devoir faire une copie de la variable alors qu'elle existe déjà bel et bien et ne ferait plus rien d'autre que de disparaitre (si on l'a laisse faire).

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 128
    Points : 33 052
    Points
    33 052
    Billets dans le blog
    4
    Par défaut
    C'est plutôt étrange de vouloir garder trace de quelque chose qui "ne ferait plus rien d'autre que de disparaitre"

  11. #11
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 669
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 669
    Points : 10 674
    Points
    10 674
    Par défaut
    Citation Envoyé par Bousk Voir le message
    C'est plutôt étrange de vouloir garder trace de quelque chose qui "ne ferait plus rien d'autre que de disparaitre"
    D'où l’intérêt des collections contenant des pointeurs

  12. #12
    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
    Citation Envoyé par Sergejack Voir le message
    sauf que je sais que c'est invalide en l'état et je trouverai dommage de devoir faire une copie de la variable alors qu'elle existe déjà bel et bien et ne ferait plus rien d'autre que de disparaitre (si on l'a laisse faire).
    Tu peux le déplacer en C++11, .push_back avec une rvalue reference.

    @foetus > boost::ptr_vector et autres sont surtout utiles pour le polymorphisme d'héritage (et que ça ?). Dans tous les cas il ne sont pas là pour sauvegarder un objet temporaire.

  13. #13
    Membre éclairé

    Homme Profil pro
    Non disponible
    Inscrit en
    Décembre 2012
    Messages
    478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Non disponible

    Informations forums :
    Inscription : Décembre 2012
    Messages : 478
    Points : 877
    Points
    877
    Billets dans le blog
    1
    Par défaut
    Bonsoir,

    Citation Envoyé par Iradrille Voir le message
    Note tout de même que si tu ne cherches pas à en faire une copie, ceci est possible
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void addObject(myObject & o, int i) {
    	o.setI(i); // ce n'est à priori pas de rôle de addObject de modifier o (tu ne modifie plus une copie de o)
    	myVector.push_back(&o);
    }
    Mais lorsque l'objet passé par référence est détruit (en fin d'accolade), le pointeur stocké dans le vecteur (portant cette même adresse) n'en n'ai pas affecté ?!
    L'adresse ne peut être réatribuée ou que sais-je ?

  14. #14
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par PilloBuenaGente Voir le message
    Bonsoir,

    Mais lorsque l'objet passé par référence est détruit (en fin d'accolade), le pointeur stocké dans le vecteur (portant cette même adresse) n'en n'ai pas affecté ?!
    L'adresse ne peut être réatribuée ou que sais-je ?
    Tant que l'objet n'est pas détruit, pas de problème.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    myObject a;
    Conteneur ctn;
    ctn.addObject(a, 0);
    {
       myObject b;
       ctn.addObject(b, 0);
    } // b détruit ici, le pointeur devient invalide à ce moment là
    // le pointeur sur a est par contre toujours valide.
    Tout dépend de combien de temps vit l'objet. Apparemment c'est un objet temporaire qui est passé à la fonction, on est dans le cas de "b", et les pointeurs ne seront pas valides dans le vector.

    Ça n'aurait posé aucun soucis si les objets vivaient plus longtemps que le vector.

  15. #15
    Membre éclairé

    Homme Profil pro
    Non disponible
    Inscrit en
    Décembre 2012
    Messages
    478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Non disponible

    Informations forums :
    Inscription : Décembre 2012
    Messages : 478
    Points : 877
    Points
    877
    Billets dans le blog
    1
    Par défaut
    Ok merci pour la précision.

    Ce n'est pas un peut risqué cette méthode ?
    Car je vois difficilement comment contrôler la validité de ces pointeurs.
    (En cherchant l'accolade ?!)

  16. #16
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Bah ça sera une décision de design : il y à forcément quelqu'un qui sera responsable de ces objets.

    "Extraire un pointeur" d'une ref comme ici sous entend que le conteneur ne possède pas les objets mais qu'il garde seulement la possibilité de les utiliser, il faut par contre lui fournir la garantie que les objets vivront plus longtemps que lui (ou au strict minimum, que même s'il garde un pointeur sur un objet supprimé, qu'il n'aura jamais à accéder à un élément supprimé).

    Si on ne peut pas fournir cette garantie, les weak_ptr peuvent aider.

    Un cas simple où l'on a cette garantie.
    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
    struct Obj { };
     
    struct Conteneur {
       std::vector<Obj*> objs;
       void add(Obj& o) {
          objs.push_back(&o);
       }
    };
     
    struct Truc {
       std::vector<Conteneur> ctns;
       std::vector<Obj> objs;
     
       Truc() : ctns(2), objs(2) {
          // tant qu'on ne redimensionne pas le vector, l'adresse des objets qu'il contient est fixe.
          for(auto & o : objs) {
             ctns[0].add(o);
             ctns[1].add(o);
          }
       }
    };
    Oui, cet exemple ne fait pas grand chose d'utile ^^"

  17. #17
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    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 381
    Points : 41 582
    Points
    41 582
    Par défaut
    "Extraire un pointeur" d'une ref comme ici sous entend que le conteneur ne possède pas les objets mais qu'il garde seulement la possibilité de les utiliser
    Euh pour moi, passer un paramètre par référence plutôt que pointeur à une fonction autre qu'un constructeur sous-entend qu'il n'aura aucune dépendance vers l'objet référencé une fois que la fonction retournera (ce qui, dans le cas présent, est faux). Franchement, pour ce genre de chose je passerais un pointeur, pour bien marquer qu'une dépendance persiste.

  18. #18
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Je n'aime pas la solution qui consiste à donner à un conteneur des pointeurs vers des objets qu'il ne contrôle pas ; à la seconde où l'objet sera détruit par un autre bout de code sans passer par le conteneur, qui du coup ne maîtrise rien, on pourra se retrouver avec des références invalides au sein du conteneur, et sur un code de plusieurs dizaines milliers de lignes par exemple, comment être sûr que personne n'oubliera jamais de faire pointer le pointeur de l'objet détruit et stocké dans le conteneur vers nullptr ?

    Selon la taille de l'objet à stocker, on déconseille d'utiliser un conteneur de copies, mais pour le coup (dans le contexte de ce qui a l'air d'une reprise de code) c'est ce que je ferais personnellement (vu que l'OP a écarté les smarts pointers si j'ai bien lu):

    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
     
    #include <iostream>
    #include <vector>
     
    using namespace std;
     
    struct Foo
    {
        int bar;
        Foo() : bar(42) {}
    };
     
    void addObject(vector<Foo>& myVector)
    {
        myVector.push_back(Foo());
    }
     
    int main()
    {
        vector<Foo> v;
        addObject(v);
        cout << "valeur 0 => " << v.at(0).bar << endl;
        return 0;
    }
    Edit : J'ai mal lu, l'OP écarte la solution de stocker des objets plutôt que des pointeurs. Je dirais alors que la solution est inévitablement l'utilisation d'unique_ptr.

  19. #19
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    @Médinoc, effectivement passer un pointeur est plus clair, my bad.

    @Kaamui, En mettant de coté la taille des objets, la copie complète pour éviter les références n'est pas forcément une solution, si on a besoin d'avoir une "référence" (au sens large, un pointeur rempli ce rôle) sur un objet existant, la mise à jour de tous les conteneurs à la moindre modification d'un objet peut vite devenir lourde.

    Il faut voir le rapport taille des objets / taux de modification / lecture : pour des objets légers (de la taille d'un pointeur par exemple) qui seraient lus 1 000 000 de fois entre chaque modification (et avec relativement peu de copies), ça peut être une bonne idée d'en garder des copies pour améliorer la localité des données. Mais c'est plus un problème d'optimisation qu'autre choses.

    Un std::unique_ptr est une bonne solution si on stocke une copie et qu'on a besoin de stocker des pointeurs (polymorphisme par exemple) -> le conteneur possède (au sens fort, il a droit de "vie et de mort" sur) les objets. C'est le cas de l'OP. Sans avoir besoin de pointeurs, stocker des objets est valide (toujours pareil, faut voir le rapport : taille des objets / nombre de redimensionnement du conteneur).

    Si on a besoin d'une référence sur un objet existant (-> le conteneur ne supprimera pas les objets, il peut seulement les lire et (éventuellement) les modifier) :
    Un pointeur nu (ou un std::reference_wrapper) est suffisant si on a la garantie que les données sont (et resteront) valides.
    Sans cette garantie, le couple std::shared_ptr / std::weak_ptr est, imo, la meilleure solution.

  20. #20
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Pas mieux

    Je ne connaissais pas le reference_wrapper. Est-ce une version intelligente du pointeur nu ?

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Comment stocker une image dans une base de données sqlce ?
    Par ozeon dans le forum Développement
    Réponses: 3
    Dernier message: 11/07/2016, 20h13
  2. Réponses: 3
    Dernier message: 20/09/2010, 14h55
  3. Comment stocker une valeure ecrite dans un JFrame
    Par aphilippartd dans le forum Débuter
    Réponses: 3
    Dernier message: 12/12/2008, 18h10
  4. Comment stocker une requête sql dans une variable ?
    Par innova dans le forum MS SQL Server
    Réponses: 5
    Dernier message: 26/10/2006, 10h01
  5. Comment stocker des mots clés dans une bas Mysql
    Par renofx1 dans le forum SQL Procédural
    Réponses: 5
    Dernier message: 05/01/2006, 00h57

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