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 :

Passage de std::pair en paramètre fail !


Sujet :

C++

  1. #1
    Membre éclairé
    Avatar de Captain'Flam
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2011
    Messages
    273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 273
    Billets dans le blog
    1
    Par défaut Passage de std::pair en paramètre fail !
    Bonjour,

    encore une énigme comme le c++ en a le secret !

    Suivant que je construise une pair (avec make_pair) dans une fonction ou au moment de la passer en paramètre, je n'ai pas la même chose !

    Voilà un petit code minimaliste de démonstration :
    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
    #include <iostream>
    using namespace std ;
     
    struct foo
        {
        foo ( int xx )  
            { 
            x = xx ;
            y = xx+1 ;
            }
     
        pair<const foo&,int> more () const 
            { 
            return make_pair<const foo&,int>( *this,7 ) ;
            }
     
        int x,y ;
        };
     
    ostream & operator<< ( ostream & o , std::pair<const foo&,int> p )
        {
        o << p.first.x << "," << p.first.y << " + " << p.second ;
        return o ;
        }
     
    int main ()
        {
        foo f ( 123 ) ;
        cout << make_pair<const foo&,int>( f,11 )  << endl ; // affiche bien 123,124 + 11
        cout << f.more()  << endl ;                                   // affiche n'importe quoi ! (ex : 1231321,6543213 + 7)
        return 0 ;
        }
    Ça ressemble au bug du débutant qui renvoie une référence sur un objet de la pile, mais en toute logique non !
    Et si c'est bien ça, comment faire ?

    Merci d'avance

    PS : Je compile sous Visual Studio 2010... au cas où il faille suspecter quelque lacune d'implémentation des stl.

  2. #2
    Membre Expert
    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
    Par défaut
    Hello,

    La seule façon de stocker une référence dans un conteneur (vector / pair / etc...) c'est de passer par std::reference_wrapper (ou équivalent).
    Tu fais actuellement une copie dans ta fonction more.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    pair<reference_wrapper<const foo>,int> more () const 
    { 
    	return make_pair(reference_wrapper<const foo>(*this), 7) ;
    }
    edit : Maintenant, j'aimerai savoir ce qu'il se passe exactement parce que je comprend pas tout.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    pair<const foo&,int> more () const 
    { 
    	pair<const foo&,int> a = make_pair(*this, 7);
    	pair<const foo&,int> b = a;
    	// pourquoi a et b sont valide ici ?
    	return b;
    }
    int main ()
    {
    	foo f ( 123 ) ;
    	// mais p invalide ici ?
    	pair<const foo&,int> p = f.more();
    }
    Pour moi, a et b devraient être invalides, ou si a et b sont valides, p devrait l'être aussi.

  3. #3
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Voila ce qu'il se passe (en reprenant l'exemple d'Iradrille) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    pair<const foo&,int> more () const 
    { 
      pair<const foo&,int> a = make_pair(*this, 7); // (1) make_pair copie *this (voir référence ci-dessous)
                       // (2) a.first est une référence vers un objet local de make_pair, comme tout accès invalides à des références, ça peut planter ou pas...
      return a;
    }
    int main ()
    {
      foo f ( 123 ) ;
      pair<const foo&,int> p = f.more(); // (3) p est toujours invalide vu que c'était déjà invalide en (2)
    }
    ref make_pair : http://en.cppreference.com/w/cpp/utility/pair/make_pair

    note qu'en utilisant le constructeur de std::pair, il ne doit pas y avoir de problème. Après je ne le conseillerais pas...

  4. #4
    Membre Expert
    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
    Par défaut
    Si je comprend bien, une copie de l'objet est passée à std::make_pair, et une pair temporaire est créée (de type std::pair<foo, int>). Puis le constructeur par copie de pair prend une ref sur la copie de l'objet pour créer la pair "a", et enfin la paire temporaire est détruite.
    Et donc la ref pointe sur un objet détruit, mais toujours présent sur la pile tant qu'on écrit pas par dessus. (-> d'ou a et b "valides")

    Je savais qu'il fallait passer par std::ref / std::refence_wrapper, maintenant je saurai pourquoi. Merci

  5. #5
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    Si je comprend bien, une copie de l'objet est passée à std::make_pair, et une pair temporaire est créée (de type std::pair<foo, int>).
    Une paire temporaire n'est pas forcément créée, le point important est qu'on assigne une copie de l'objet (qui est local à la fonction make_pair) à pair.first de type const&, par conséquent la référence pointera sur un objet local à make_pair.

Discussions similaires

  1. Passage de std::string en paramètre
    Par Keweed dans le forum Débuter
    Réponses: 11
    Dernier message: 31/10/2009, 10h22
  2. Passage de tableau dynamique en paramètre
    Par Didier L dans le forum Langage
    Réponses: 3
    Dernier message: 08/09/2005, 23h04
  3. Passage d'une requete en paramètre dans un delete
    Par jlamazou dans le forum MS SQL Server
    Réponses: 1
    Dernier message: 03/08/2005, 17h58
  4. Réponses: 6
    Dernier message: 26/07/2005, 10h20
  5. Réponses: 7
    Dernier message: 18/05/2005, 15h09

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