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 :

Trimballer un unique_ptr avec la sémantique de mouvement


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut Trimballer un unique_ptr avec la sémantique de mouvement
    Hello,

    J'aune classe dotée d'un membre constant de type unique_ptr, qui la plupart du temps ne sera pas associé à une donnée (pointera donc sur null). POur les cas où il doit l'être, l'initialisation se fait via un argument du constructeur, qui a une valeur par défaut (nullptr).

    Question 1 :
    Cet argument optionnel devrait-il être de type pointeur ou unique_ptr ? J'aurais tendance à opter pour le second (car l'utilisateur qui a assigné le pointeur ne fait pas face à une ambiguité sur le devenir de l'emplacement mémoire), mais cela induit à se poser des questions sur le coût de la construction (?) par rapport à un nullptr.

    Question 2 :
    La valeur du pointeur (ou de l'unique_ptr) est indiquée très loin en amont (l'argument est passé via 4 fonctions en cascade). Je pensais me mettre à la sémantique de mouvement, mais comment mettre ça en œuvre ? Les fonctions prendraient un unique_ptr<>&& ? Et l'argument est donné avec un std::move() ?

    Merci.

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    J'ai fait un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct MaClasse
    {
        MaClasse(std::unique_ptr<int>&& unEntier = nullptr) :
            m_Entier(std::move(unEntier ))
        { }
        std::unique_ptr<int>m_Entier;
    };
    Est-ce la bonne méthode ?

  3. #3
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par défaut
    Je pense que le mieux est plutôt de passer l'unique_ptr par valeur, pour bien garantir que l'ownership a été transféré :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    struct MaClasse
    {
        MaClasse(std::unique_ptr<int> unEntier = nullptr) :
            m_Entier(std::move(unEntier ))
        { }
        std::unique_ptr<int>m_Entier;
    };
    Explication ici :

    http://stackoverflow.com/questions/8...-or-a-function

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    En fait, comme unique_ptr est non copiable, les passages par valeur et par r-value ont-ils une réelle différence ?

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

    Informations professionnelles :
    Activité : aucun

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

    Contrairement à l'explication donnée sur stackoverflow, je dirais qu'il faudrait mieux passer le pointeur nu (mais ne même pas faire appel à move).

    Mais avant d'aller plus loin, je dois préciser que je considère généralement que le unique_ptr n'est qu'un "détail d'implémentation" de la classe qui le manipule.

    Cette manière de considérer les choses oriente -- fatalement -- ma réflexion

    Je trouves en effet dommage d'exposer un tel détail d'implémentation s'il est possible de l'éviter, fusse au niveau du constructeur.

    Partant de là, je me dis que l'utilisateur n'a strictement aucun besoin de savoir sous quelle forme le pointeur sous-jacent est géré en interne par la classe et que c'est à la classe qui manipule le unique_ptr de savoir si elle transfère la propriété du pointeur sous-jacent ou si elle ne fait que le "prêter" dans le cadre d'une utilisation particulière, quitte à ce qu'elle expose deux comportements correspondant au deux possibilités:
    • un comportement "release" qui appelle la fonction équivalente au niveau du unique_ptr (qui a pour résultat de libérer la propriété du pointeur sans le détruire, pour permettre de transférer cette propriété) et
    • un comportement "get" (ou tout ce que tu veux d'autre) qui appelle la fonction équivalente au niveau de unique_ptr (qui a pour résultat de renvoyer le pointeur nu, tout en permettant au unique_ptr de garder la propriété du pointeur)
    (si tant est que cela ait du sens de permettre à l'utilisateur de récupérer le pointeur sous-jacent sous l'une ou l'autre forme, chacune d'elles n'étant ni automatique ni exclusive bien sur )

    Autrement dit, mon raisonnement tend à faire en sorte que l'utilisateur puisse passer un pointeur dont il sait qu'il n'est la propriété de rien au constructeur de la classe dont il sait que la classe prendra la propriété du pointeur en question sans avoir à s'inquiéter de "la popote interne" qui permettra à la classe en question d'acquérir la propriété de ce pointeur, et sans avoir à s'inquiéter de savoir si la classe en question des prête à "partager" le pointeur ou non .

    A l'utilisation, c'est donc à l'utilisateur de savoir, selon ce que la classe lui permet de faire, s'il veut transférer la propriété du pointeur sous-jacent ou non
    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

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Avec un pointeur nu, on ne sait pas qui est supposé se charger de la libération de la ressource allouée par le pointeur. L'utilisateur va fatalement se poser la question : "est-ce à moi de désallouer ?"

  7. #7
    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
    Citation Envoyé par koala01 Voir le message
    Mais avant d'aller plus loin, je dois préciser que je considère généralement que le unique_ptr n'est qu'un "détail d'implémentation" de la classe qui le manipule.

    Cette manière de considérer les choses oriente -- fatalement -- ma réflexion

    Je trouves en effet dommage d'exposer un tel détail d'implémentation s'il est possible de l'éviter, fusse au niveau du constructeur.
    Je réagi la dessus, je trouve le passage de pointeur à un constructeur peut clair : on est obligé de se réferrer à la doc pour savoir si l'objet créé devient propriétaire (et donc delete le pointeur correctement en fin vie) du pointeur passé en paramètre ou pas.
    Avec un unique_ptr il n'y à pas de doute possible.

    C'est plus qu'un détail d'implémentation, c'est un "morceau de documentation intégré au prototype de la fonction"

  8. #8
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par défaut
    Citation Envoyé par oodini Voir le message
    En fait, comme unique_ptr est non copiable, les passages par valeur et par r-value ont-ils une réelle différence ?
    Oui, une petite différence : Le passage par valeur force le transfert de l'unique_ptr (car force la création d'un unique_ptr par constructeur de mouvement), alors que le passage par rvalue-reference non. Une r-value reference reste une référence avant tout, le corps de la fonction peut donc s'en servir comme une référence classique par exemple uniquement en la lisant.

    Par exemple avec le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void foo(std::unique_ptr<int> = nullptr){}
    auto iptr = std::make_unique<int>(42);
    //foo(iptr); // ne compile pas, copie interdite
    foo(std::move(iptr));
    // iptr vide ici
    Sans même regarder l'implémentation de foo() (qui ici est vide) l'appelant a la garantit que iptr est forcement mis à nullptr en sorti de foo(). La valeur sous-jacente a été transférée dans foo.
    Alors qu'avec le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void foo(std::unique_ptr<int>&& = nullptr){}
    auto iptr = std::make_unique<int>(42);
    //foo(iptr); // ne compile pas, copie interdite
    foo(std::move(iptr));
    // iptr inchangé !
    on a comportement complètement contre-intuitif, on vient d'écrire un "move" et pourtant la valeur d'iptr n'a pas du tout changé !

    C'est pour ça que je disais que le passage par valeur est un peu plus clair sur le transfert d'ownership, car l'appelant a la garantit qu'un unique_ptr passé à une fonction qui prend par valeur est vide après l'appel à la fonction et donc qu'il n'en a plus la responsabilité.

Discussions similaires

  1. Problème avec la sémantique de "transient"
    Par professeur shadoko dans le forum Langage
    Réponses: 10
    Dernier message: 06/06/2014, 15h24
  2. Collisions avec un objet en mouvement
    Par xoux28 dans le forum Tkinter
    Réponses: 15
    Dernier message: 30/03/2014, 11h49
  3. Réponses: 1
    Dernier message: 14/05/2012, 18h54
  4. ouverture avec une interpolation de mouvement d'une fenetre
    Par escteban dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 19/06/2007, 17h04

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