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++

  1. #81
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par gl Voir le message
    J'ai beaucoup de mal avec ton exemple car je ne vois pas ce que tu cherches vraiment à montrer.
    Je ne suis donc pas le seul. J'ai l'impression de participer à un dialogue de sourds. Je vais donc remettre ma thèse en deux phrases et si Koala01 en faisait autant, on arriverait peut-être à se comprendre.

    À partir du moment où il est décidé qu'un composant doit prendre seul en charge la responsabilité de libérer un pointeur sans que cette responsabilité s'accompagne de celle de notifier d'autres participants de la libération, le meilleur moyen est qu'il prenne un unique_ptr<T> en paramètre (par valeur si la prise est irrévocable, par rvalue-reference s'il peut jeter une exception et veut fournir la garantie forte).

    À partir du moment où il est décidé qu'un composant doit transmettre la responsabilité de libérer un pointeur sans que cette responsabilité soit partagée avec d'autres participants, le meilleur moyen est qu'il retourne un unique_ptr<T>.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Et ma thèse est que, que ce soit explicite ou implicite, cela va, de toutes manière se propager comme une trainée de poudre tout au long du projet.

    Autrement, tu ne pourras jamais avoir la certitude que la fonction qui appelle la fonction qui appelle la fonction qui manipule le unique_ptr n'essayera pas de manipuler le pointeur nu après être passé par le chemin qui a provoqué la création du pointeur intelligent.

    Dés lors, la question est "pourquoi faudrait il rajouter une exception à la une règle de codage si cette exception va, de toutes manières, se répandre de proche en proche à l'ensemble du projet "

    En schématisant à peine tu as une règle qui te dit
    A chaque new doit correspondre un delete sauf
    1. fonction1 (qui prend un unique_ptr)
    2. fonction2 (qui renvoie un unique_ptr)
    3. fonction3 (qui prend un unique_ptr et qui en renvoie un)
    4. fonction4 (...)
    5. ...
    6. fonctonN(...)
    Et, au final, on se rend compte que l'on couvre l'ensemble du projet avec toutes ces exceptions.

    Quand une règle générale n'est plus adaptée (parce qu'elle présente plus de situations exceptionnelles que de situations de base), surtout si, pour matérialiser cette exception, nous devons commencer à exposer quelque chose qui n'est qu'un "détail d'implémentation" (même si le détail d'implémentation possède une sémantique forte), c'est qu'il est peut être temps de changer son fusil d'épaule et d'adapter la règle générale.

    En modifiant la règle pour qu'elle ressemble à
    tout objet devient implicitement responsable des pointeurs qu'on lui transmet sauf quelques un qui n'exposent aucun des comportements permettant de se défaire de cette responsabilité
    tu te retrouves avec une règle générale et quelques exceptions (si tant est qu'il y en ait) et tu peux te contenter de n'exposer que des comportements qui peuvent parfaitement être basés sur des pointeurs au lieu d'être basés sur "le détail d'implémentation" qu'est le unique_ptr.

    Dés lors, pourquoi ne pas prendre la solution la plus simple et se contenter de modifier la règle, au lieu de vouloir systématiquement passer / renvoyer un unique_ptr (ou un shared_ptr, car ce sera le même combat)
    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. #83
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    J'ai vraiment du mal à voir ce que tu veux prouver Koala01. Tu es le seul à parler d'exception à une règle, pour nous il n'y en a pas. Du moins je n'en vois pas dans les 2 lignes (ie la règle) de Jean-Marc :
    • StrictOwnership au passage : std::unique_ptr ou std::unique_ptr&& (le choix entre les deux est une autre discussion)
    • StrictOwnership au retour : std::unique_ptr

    Par contre dans ta règle, tu as des exceptions :
    • Pointeur nu au passage : StrictOwnership, sauf exceptions [1]


    Je vais juste faire une remarque :
    • Avec des std::unique_ptr partout (vraiment partout, plus un seul raw, plus un seul new explicite, plus un seul delete explicite), je suis d'office certain qu'à un new correspondra un delete. Je perds cette certitude quand l'utilisateur a pris la décision d'utiliser un pointeur nu quelque part et qu'il ne sait pas s'en servir.
    • Avec des pointeurs nus, je me retrouve comme en C++03, je ne suis certain de rien sans lire la documentation et/ou les commentaires [2]. Et si l'utilisateur ne sais pas se servir des pointeurs nus, j'ai aucune certitudes.


    Je ne vois pas ce que je gagne avec des pointeurs nus. Si tu n'es pas d'accord, je te propose de montrer un code avec uniquement des std::unique_ptr qui ne me permet pas d'être certain qu'il correspondra un delete à un new.

    [1]
    tout objet devient implicitement responsable (ie StrictOwnership) des pointeurs (pointeur nus) qu'on lui transmet sauf (exception) quelques un qui n'exposent aucun des comportements permettant de se défaire de cette responsabilté
    [2] Nécessairement puisque je dois vérifier qu'on est pas dans un cas d'exception.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Mais je ne vais quand même rien vous apprendre en vous disant que toute fonction, tout type ne vaut que par l'utilisation qui en est faite

    A partir du moment où vous créez un type ou une fonction, c'est pour qu'il (elle) soit utilisé(e), sinon, vous ne le (la) créeriez pas, non

    Dans cette optique, le fait de créer un type (ou une fonction) qui va explicitement prendre la responsabilité de la durée de vie d'un pointeur n'est pas aussi anodin que le fait de créer une classe ou une fonction qui va utiliser std::string au lieu d'un char *:

    Le fait d'utiliser une std::string n'aura une incidence que sur le type (la fonction) qui l'utilise et, au pire "quelques fonctions connexes", alors que le fait de prendre la responsabilité de la durée de vie aura une incidence sur l'ensemble des types et des fonctions qui manipulent ce pointeur.

    Pourquoi me demanderez vous

    Simplement parce qu'on ne sait pas ni d'où vient ce pointeur, ni par où il est passé avant d'arriver, ni où il risque d'aller après que la fonction / le type en ait pris la responsabilité.

    On ne peut donc pas se permettre de dire "je prend la responsabilité de ce pointeur, et basta", parce que cela va introduire une exception quant à la manière générale dont le pointeur est manipulé par ailleurs:

    Si l'on se contente de modifier uniquement une fonction / un type pour qu'il prenne la responsabilité du pointeur, on peut s'attendre à ce que tout ce qu'il y a en amont, en aval et sur les cotés de cette fonction / de ce type saute systématiquement suite à un comportement indéfini induit par le seul fait qu'il y a, maintenant, un type ou une fonction qui prend la responsabilité de détruire le pointeur "quand bon lui semble" (j'exagère un peu, soit, mais le résultat est identique).

    Du coup, on va commencer à corriger tous ces comportements qui sautent, en jouant au jeu du "tu me donnes la responsabilité, je l'accepte ou, non merci, je n'en ai pas besoin", mais le fait est que, de manière générale, le fait qu'un type ou une fonction ait pris la responsabilité du pointeur devra d'une manière ou d'une autre être pris en compte par l'ensemble des types et des fonctions susceptibles de manipuler ce pointeur.

    Dés lors, plutôt que de dire
    amis développeurs, vous êtes responsables des pointeurs que vous utilisez sauf si vous passez par ici, et par là ... Oh et par là aussi... Et j'ai failli oublié par ce chemin de traverse
    qui correspondront à autant d'exception à la règle, pourquoi ne pas dire
    amis développeurs, il y a d'office quelque chose qui prendra la responsabilité du pointeur.

    Libre à vous (si ce qui a la responsabilité du pointeur est d'accord) de le décharger de sa responsabilité pour la transmettre à quelque chose d'autre.
    La règle est quand même plus simple à comprendre, non

    D'autant plus que, à partir de ce moment là, la manière dont la fonction / le type gère la responsabilité du pointeur reprend sa place initiale : celle d'un détail d'implémentation, qui n'a aucun besoin d'être exposé.

    Si un type est d'accord de se défaire de la responsabilité du pointeur dont il a la charge, très bien, il expose un comportement qui correspond à l'appel de release(), s'il est d'accord pour "prêter" le pointeur en question (mais attention : je le détruis au plus tard lorsque je meure), très bien, il expose un comportement qui correspond à l'appel de get().

    Mais ca, ce sont des comportements que vous devrez de toutes manière exposer s'ils ont du sens, même si vous exposez explicitement le fait que vous utilisez un unique_ptr!

    Dés lors, je vous pose la question : pourquoi vouloir se taper sur la tête en exposant un détail d'implémentation qui vous forcera, de toutes manière à faire tout ce que vous auriez fait sans l'exposer, alors que vous auriez tout aussi bien pu vous contenter d'adapter une seule règle de travail

    Je suis, et j'ai toujours été, un adepte de la solution la plus simple. Dans le cas présent, la solution la plus simple me semble d'être d'adapter la règle de travail
    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. #85
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    J'ai l'impression qu'on est pas du tout dans la même question. La j' [et je dois pas être le seul] envisage la question sous l'angle, "le C++11 nous offre de nouveaux outils, comment je peux les utiliser directement".

    Je ne me demande pas comment transformer un code C++03 en C++11 ou comment utiliser du C++03 dans un nouveau projet C++11. Ainsi je n'envisage pas de "remplacer un raw par un smart" ou de "prendre la responsabilité d'un raw", mais plutôt dans l'esprit "comment je gères les ressources ?".

    Et la réponse à cette question est pour moi : pas de raw, jamais [1]. En particulier dans le transfert [2].

    ou un shared_ptr, car ce sera le même combat
    Non rien à voir. On parle de StrictOwnership et de transfert là, ça exclu automatiquement shared_ptr qui n'applique pas cette politique et où le transfert n'est, par conséquent, pas aussi critique.

    amis développeurs, il y a d'office quelque chose qui prendra la responsabilité du pointeur.
    Mais c'est exactement ce qu'on dit et ce qu'il se passe si j'enlève tout les pointeurs nus, new explicite et delete explicite de mon code. Je veux une ressource :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    auto widget = make_unique<T>();
    //ou a travers un factory aussi complexe que tu veux :
    auto widget = create("my_widget");
     
    //auto déduit tout seul à std::unique_ptr<T>
    //il y a d'office quelque chose
    Utilisation simple de la sémantique de pointeur :
    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
     
    //J'en ai encore besoin ensuite
    foo(widget);
    //J'en ai plus besoin ensuite
    foo(std::move(widget));
     
    //ou
    template<class Pointer>
    void foo(Pointer&& pointer);
    //il y a des variations possible
    //mais ça n'impacte pas l'utilisateur
     
    //si j'en ai plus besoin il est peut-être déduit
    //si j'en ai encore besoin il n'est pas détruit
    //il y a toujours d'office quelque chose
    Utilisation du StrictOwnership
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    //la fonction a besoin de prendre la ressource
    bar(std::move(widget));
     
    //ou
    void bar(std::unique_ptr<T>&&);
    //void bar(std::unique_ptr<T>);
    //si pas d'exception ou de résistance forte
     
    //il y a toujours d'office quelque chose
    Je ne vois pas où je dis :
    amis développeurs, vous êtes responsables des pointeurs que vous utilisez sauf si vous passez par ici, et par là ... Oh et par là aussi... Et j'ai failli oublié par ce chemin de traverse
    C'est même totalement l'inverse, la responsabilité est toujours automatique, et il n'y a aucun exception. Et je l'ai pas spécialement mis en évidence ici, mais la seul réel question de l'utilisateur c'est : "est-ce que je garde la responsabilité dans ce scope ou alors est-ce que j'en ai plus besoin ?" dans le premier cas il écrit widget, sinon std::move(widget). Et cette question je suis bien obligé de me la poser. Si par malheur j'en ai encore besoin mais que la fonction elle en a besoin, alors le compilateur me le dira [3] : aucun risque.

    [1] Evidemment c'est dans un monde idéal, puisque si j’interagis avec un bibliothèque C++03, je peux en avoir.

    [2] Sachant que l'OP était dans le cas où il a déjà des pointeurs dont la responsabilité est prise en amont, il n'a donc pas de pointeurs nus au niveau de l'appel, c'est juste au niveau du transfert que la question se pose.

    [3] Je passe un lvalue à une fonction attendant un rvalue-référence, erreur de compilation.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    J'ai l'impression qu'on est pas du tout dans la même question. La j' [et je dois pas être le seul] envisage la question sous l'angle, "le C++11 nous offre de nouveaux outils, comment je peux les utiliser directement".
    Et moi, la question que je pose est "pourquoi devrais je exposer les nouveaux outils que j'utilise alors que, de toutes manières, ils interviennent dans une logique globale "
    Je ne me demande pas comment transformer un code C++03 en C++11 ou comment utiliser du C++03 dans un nouveau projet C++11. Ainsi je n'envisage pas de "remplacer un raw par un smart" ou de "prendre la responsabilité d'un raw", mais plutôt dans l'esprit "comment je gères les ressources ?".
    Mais, que ce soit dans un cas ou dans l'autre, le problème reste le même: tu ne peux pas te contenter d'avoir une approche limitée à la classe ou à la fonction qui prend la responsabilité.

    C'est une notion qui, d'une manière ou d'une autre, devra de toutes façons être prise en compte de manière globale, parce que si tu n'en tiens pas compte de manière globale, tu te retrouveras -- fatalement -- avec une classe ou une fonction qui tentera de détruire ou d'accéder à un pointeur qui, par le fait même de la prise de la responsabilité par "autre chose", a de fortes chances d'avoir déjà été invalidé, avec les conséquences que l'on connait tous.
    Et la réponse à cette question est pour moi : pas de raw, jamais [1]. En particulier dans le transfert [2].
    Et tu vas donc "surcharger" l'ensemble de tes prototypes en passant systématiquement un (e (rvalue)référence vers) un unique_ptr à toutes tes fonctions, histoire de bien insister sur le fait que la responsabilité du pointeur est gérée par ailleurs, alors que dans, sauf cas de transfert, tu devras quand même manipuler le pointeur lui-même.
    Non rien à voir. On parle de StrictOwnership et de transfert là, ça exclu automatiquement shared_ptr qui n'applique pas cette politique et où le transfert n'est, par conséquent, pas aussi critique.
    Hummm... à voir...

    Au niveau d'un shared_ptr, c'est "le dernier en vie" qui décidera de le détruire, mais, de manière générale, si tu as une référence vers ce pointeur qui n'est pas prise en compte, le problème restera tout à fait identique : cette référence vers le pointeur risque, à un moment ou à un autre, d'essayer de détruire ou d'accéder à un pointeur qui a été invalidé.
    Je ne vois pas où je dis :
    amis développeurs, vous êtes responsables des pointeurs que vous utilisez sauf si vous passez par ici, et par là ... Oh et par là aussi... Et j'ai failli oublié par ce chemin de traverse
    Tu le dis, ou du moins, tu le laisses à penser par le simple fait que tes prototypes / signatures de fonctions exposent ton unique_ptr
    C'est même totalement l'inverse, la responsabilité est toujours automatique, et il n'y a aucun exception.
    Ce n'est pas parce que toutes tes fonctions exposent un unique_ptr (sous quelque forme que ce soit) que ne fait pas de ces fonctions des exceptions!

    Au contraire, chaque fonction qui expose un unique_ptr représente une exception à la règle commune.

    Et ce n'est qu'en ayant une approche "globale" qu'il y a moyen de se rendre compte que l'ensemble des exceptions fini par englober l'ensemble des cas couverts par la règle de base.

    Du coup, je repose la question: étant donné que la règle de base montre des faiblesses (autrement, toutes les exceptions n'auraient jamais couvert l'ensemble de son scope), pourquoi se faire du mal à créer toutes ces exceptions au lieu de simplement modifier la règle générale
    la seul réel question de l'utilisateur c'est : "est-ce que je garde la responsabilité dans ce scope ou alors est-ce que j'en ai plus besoin ?" dans le premier cas il écrit widget, sinon std::move(widget). Et cette question je suis bien obligé de me la poser.
    Ca, je suis tout à fait d'accord, l'utilisateur devra, de toutes manières se poser la question de savoir s'il garde ou non la responsabilité.

    Mais la question que je pose est : pourquoi le forcer à utiliser std::move au lieu de n'exposer que des comportements explicites quant au fait qu'il libère un objet de la responsabilité d'un pointeur

    Dois-je rappeler que la première règle de POO est de penser en terme de comportement et non en terme de données manipulées
    Si par malheur j'en ai encore besoin mais que la fonction elle en a besoin, alors le compilateur me le dira [3] : aucun risque.
    ... Et te forcera à appliquer une emplatre sur une jambe de bois, ou à prendre des décisions qui ne t'arrangent pas forcément (cf le point que j'avais abordé concernant le problème d'avoir directement transmis la responsabilité à une fonction )
    [1] Evidemment c'est dans un monde idéal, puisque si j’interagis avec un bibliothèque C++03, je peux en avoir.
    Encore une fois, cela prouve que tu dois avoir une approche globale
    [2] Sachant que l'OP était dans le cas où il a déjà des pointeurs dont la responsabilité est prise en amont,
    ... ou pas...

    Elle peut être prise en amont, en aval, et même sur les cotés

    Tout dépendra du moment auquel ta classe prendra la responsabilité du pointeur dans le flux d'exécution global, et tu n'as aucune garantie que ce moment arrivera "au début du flux d'exécution", comme ce devrait être le cas en toute logique.
    il n'a donc pas de pointeurs nus au niveau de l'appel, c'est juste au niveau du transfert que la question se pose.
    En théorie, je ne peux être que d'accord avec toi.

    Mais cela ne justifie, à mon sens, pas forcément d'exposer le fait que l'on manipule un unique_ptr car, encore une fois, tout peut être réglé beaucoup plus facilement en adaptant simplement la règle générale qui a de toutes manière montré ses limites
    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

  7. #87
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Moi, je comprend que tu aimerais un unique_ptr qui pourrais se transformer en weak_ptr dés que quelqu'un prend possession.

    Et c'est pourquoi tu parle de Qt. Avec addWidget tu donne la gestion de vie à quelqu'un mais tu veux toujours pouvoir y accéder:
    1- Ce qui n'est pas possible avec un unique_ptr.
    2- un shared ne va pas car un widget ne peux pas être enfant de 2 widgets.

  8. #88
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par yan Voir le message
    Moi, je comprend que tu aimerais un unique_ptr qui pourrais se transformer en weak_ptr dés que quelqu'un prend possession.
    Je n'ai jamais dit cela!!!

    Au contraire, je suis particulièrement critique au sujet du couple shared_ptr /weak_ptr, parce que je trouve risqué d'avoir une responsabilité partagée, qui risque de mener à des confusions du genre de "mais ce pointeur est sensé avoir été détruit" (alors que l'on a oublié un objet toujours en vie dans un coin) ou du genre de "mais ce pointeur est sensé encore être valide"(alors qu'on a oublié que tous les objets qui le maintenaient ont été détruits).

    Il n'empêche que les problèmes susceptibles d'arriver lorsqu'un unique_ptr prend possession d'un pointeur sont tout aussi susceptibles d'arriver lorsque c'est un shared_ptr qui en prend possession.

    Ma comparaison entre les deux s'arrête là, et je ne fais aucune
    Et c'est pourquoi tu parle de Qt. Avec addWidget tu donne la gestion de vie à quelqu'un mais tu veux toujours pouvoir y accéder:
    1- Ce qui n'est pas possible avec un unique_ptr.
    Et pourquoi pas

    Ce n'est pas parce qu'un objet prend sur lui de décider de la vie et de la mort d'un pointeur que le pointeur en question doit être limité au seul usage de l'objet!

    La seule chose à laquelle il faille faire attention, c'est au fait que tout ce qui manipule le pointeur aura bel et bien terminé son job lorsque l'objet décidera de détruire le pointeur.

    Autrement dit, que la prise de possession du pointeur s'effectuera au tout début du flux d'exécution dans lequel le pointeur ira se balader
    2- un shared ne va pas car un widget ne peux pas être enfant de 2 widgets.
    Ai-je jamais dit nulle part qu'un widget peut etre enfant de deux autres widgets

    La seule chose que j'ai dite au sujet de Qt c'est : à partir du moment où l'on a donné un widget à un autre, c'est cet autre objet qui en prend la responsabilité, on n'a aucun besoin de savoir comment cela fonctionne en interne, et c'est une bonne chose.

    Et, encore une fois, la comparaison s'arrêtait là.
    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

  9. #89
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Je n'ai jamais dit cela!!!
    Comme je l'ai dit, c'est ce que je comprend au bout de toutes tes explications mais je peux me tromper. La discutions est un peu difficile à suivre

    Il n'empêche que les problèmes susceptibles d'arriver lorsqu'un unique_ptr prend possession d'un pointeur sont tout aussi susceptibles d'arriver lorsque c'est un shared_ptr qui en prend possession.
    ...
    Et pourquoi pas
    Une fois que le pointeur est transféré, l'ancien unique_ptr est null. Donc tu n'as plus un accès directe à l'objet. Contrairement à un pointeur mais qui pourrais être devenue invalide.

    Ai-je jamais dit nulle part qu'un widget peut etre enfant de deux autres widgets
    J'explique juste pourquoi le shared n'est pas une option dans ce cas précis.

    J'ai vraiment l’impression que tu défend le pointeur car tu as besoin d'un truc entre l'unique_ptr et le share_ptr.

  10. #90
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par koala01 Voir le message
    La seule chose que j'ai dite au sujet de Qt c'est : à partir du moment où l'on a donné un widget à un autre, c'est cet autre objet qui en prend la responsabilité, on n'a aucun besoin de savoir comment cela fonctionne en interne, et c'est une bonne chose.
    Pourtant la plupart des erreurs mémoire avec Qt sont produitent parceque la personne ne sait pas un minimum ce qui se passe.
    - double delete ou acces sur un QObject qui as été détruit par une hierarchie de QObject.

    - mémoire non désalloué, on m'as pourtant dit que Qt géré lui même toute la mémoire

    Et Qt as essayé de donner des smartpointeur pour simplifier tous cela :
    http://qt-project.org/doc/qt-5.1/qtc...r.html#details
    http://qt-project.org/doc/qt-4.8/qwe...QWeakPointer-4

  11. #91
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par yan Voir le message
    J'ai vraiment l’impression que tu défend le pointeur car tu as besoin d'un truc entre l'unique_ptr et le share_ptr.
    Je ne défend pas le pointeur nu en tant que tel, et je n'ai pas besoin d'un truc qui serait entre unique_ptr et shared_ptr.

    Ce que je défend, c'est la thèse selon laquelle unique_ptr et shared_ptr ne sont que des détails d'implémentation dont l'utilisateur ne devrait pas avoir à s'inquiéter autrement que par les comportements proposés par les fonctions et les types qui les manipulent:

    Quand un objet prend l'unique responsabilité d'un pointeur, il prend cette responsabilité, point barre. L'utilisateur n'a pas à s'inquiéter de savoir si c'est sous la forme d'un std::unique_ptr ou sous la forme d'une quelconque forme d'implémentation similaire.

    Tout ce dont l'utilisateur a à s'inquiéter, c'est de savoir si l'objet en question est d'accord pour prêter le pointeur (en en gardant la responsabilité) et / ou s'il est d'accord de se défaire de cette responsabilité.

    Et ca, ben l'utilisateur le saura en fonctions des comportements que l'objet expose :
    • S'il rencontre une fonction get() ou similaire, l'objet est d'accord pour prêter le pointeur en en gardant la responsabilité
    • S'il rencontre une fonction release() ou similaire, l'objet est d'accord de se défaire de la responsabilité.
    Il n'y a, à mon sens, pas besoin d'exposer d'avantage les choses que cela.
    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

  12. #92
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par yan Voir le message
    Pourtant la plupart des erreurs mémoire avec Qt sont produitent parceque la personne ne sait pas un minimum ce qui se passe.
    - double delete ou acces sur un QObject qui as été détruit par une hierarchie de QObject.
    Ce n'est pas la panacée, je te l'accorde...

    Il manque, très certainement, de la visibilité sur le fait que chaque fois que tu définis un parent pour un de tes pointeurs, le parent prend en charge la responsabilité de sa destruction
    Mais cela n'en rend pas le reste invalide pour autant.

    J'ai moi meme réexpliqué le principe suffisamment souvent
    - mémoire non désalloué, on m'as pourtant dit que Qt géré lui même toute la mémoire
    De la même manière, il manque très certainement de la visibilité sur le fait que, pour que cela puisse marcher correctement, il faut que tu aies clairement défini le parent de ton pointeur.

    Mais, à partir du moment où tu as expliqué ce principe à quelqu'un, à partir du moment où tu lui a permis de prendre conscience de ce principe, il ne perdra plus son temps à se poser la question ni dans un sens ni dans l'autre

    Et il n'y a pas besoin d'exposer autre chose que les comportements qui permettent de mettre la mécanique en place
    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

  13. #93
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Mais, à partir du moment où tu as expliqué ce principe à quelqu'un, à partir du moment où tu lui a permis de prendre conscience de ce principe, il ne perdra plus son temps à se poser la question ni dans un sens ni dans l'autre

    Et il n'y a pas besoin d'exposer autre chose que les comportements qui permettent de mettre la mécanique en place
    Combien de personne que tu as aidé ont réellement compris du premier coup?
    Moi pas beaucoup.

    Qt en proposant sa gestion mémoire peut embrouiller les esprits. Et même pire cette embrouillage peut leurs faire créer des erreurs dans d'autre code C++.

    Des smartpointeur (autre que unique_ptr et shared_ptr) pourraient éviter pas mal d'erreur et justement exposer le comportement ou diriger le développeur pour bien utiliser une lib.

  14. #94
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par yan Voir le message
    Combien de personne que tu as aidé ont réellement compris du premier coup?
    Moi pas beaucoup.
    Apparemment, toutes
    Qt en proposant sa gestion mémoire peut embrouiller les esprits. Et même pire cette embrouillage peut leurs faire créer des erreurs dans d'autre code C++.
    En C++03, très certainement, parce qu'on leur surine à longueur de journée que "à chaque new doit correspondre un delete".

    Ce qui est vrai tant que l'on ne dispose pas des pointeurs intelligents.

    J'espère sincèrement qu'avec C++11, la règle que l'on surinera aux gens deviendra
    A chaque new doit correspondre un pointeur intelligent équivalent
    Mais, cela ne veut absolument pas dire qu'il faille exposer ce pointeur intelligent, pas plus qu'il faille exposer le delete sur le pointeur : Au lieu d'avoir une classe qui appelle explictement delete au niveau du destructeur, tu crées une classe qui manipule en interne le pointeur intelligent qui correspond à tes besoins (qui se chargera de le détruire en temps et en heure) et qui expose les comportements dont tu as besoin

    Quelque part, C++11 n'a fait que fournir un moyen d'appliquer ce que de nombreuses bibliothèques ont déjà compris depuis longtemps (car il n'y a pas que Qt dans le lot, mais aussi boost et sans doute la très grosse majorité des bibliothèques IHM un tant soit peu "modernes")
    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

  15. #95
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Désolé de prendre la discussion au vol, j'étais en vacances, et n'ai que survolé les réponses précédentes.
    Citation Envoyé par koala01 Voir le message
    Je ne défend pas le pointeur nu en tant que tel, et je n'ai pas besoin d'un truc qui serait entre unique_ptr et shared_ptr.

    Ce que je défend, c'est la thèse selon laquelle unique_ptr et shared_ptr ne sont que des détails d'implémentation dont l'utilisateur ne devrait pas avoir à s'inquiéter autrement que par les comportements proposés par les fonctions et les types qui les manipulent:

    Quand un objet prend l'unique responsabilité d'un pointeur, il prend cette responsabilité, point barre. L'utilisateur n'a pas à s'inquiéter de savoir si c'est sous la forme d'un std::unique_ptr ou sous la forme d'une quelconque forme d'implémentation similaire.
    Le fait que la prise de responsabilité soit indiqué dans le code permet d'éviter des erreurs d'étourderies, par rapport à une prise de responsabilité qui ne serait indiquée que par des commentaires. Ça ne rend pas une mauvaise utilisation impossible, bien entendu, mais ça la rend plus difficile. Et je préfère que ce genre de documentation soit dans le code, comprise par les compilateurs, les outils d'analyse, et les développeurs, que plus ou moins bien formulée dans un commentaire (quand le code est commenté) ou une convention de nommage (je crois que c'est ce que tu proposes par la suite).
    C'est d’ailleurs pour ça que je défends l'idée d'un smart pointeur qui ne permettrait que d'observer l'objet, mais pas d'en prendre la responsabilité, là où T* est un type fourre-tout qui n'indique rien sur le rôle du paramètre. Passer un unique_ptr au lieu d'un T* a pour moi le même rôle que de prendre un paramètre de type T* au lieu de void* : Donner plus d'informations à tout le monde pour que le code soit correct.
    Citation Envoyé par koala01 Voir le message
    Tout ce dont l'utilisateur a à s'inquiéter, c'est de savoir si l'objet en question est d'accord pour prêter le pointeur (en en gardant la responsabilité) et / ou s'il est d'accord de se défaire de cette responsabilité.


    Et ca, ben l'utilisateur le saura en fonctions des comportements que l'objet expose :
    • S'il rencontre une fonction get() ou similaire, l'objet est d'accord pour prêter le pointeur en en gardant la responsabilité
    • S'il rencontre une fonction release() ou similaire, l'objet est d'accord de se défaire de la responsabilité.
    Il n'y a, à mon sens, pas besoin d'exposer d'avantage les choses que cela.
    Là, tu es en train de parler de comment l'objet donne accès à des pointeurs qu'il possède. J'avais l'impression que la discussion initiale était plus de comment transférer à un objet la responsabilité d'un autre.

    Citation Envoyé par koala01 Voir le message
    Apparemment, toutes
    En C++03, très certainement, parce qu'on leur surine à longueur de journée que "à chaque new doit correspondre un delete".
    Je n'ai pour ma part jamais dit ça, même en C++03. Déjà car C++03 permet déjà des smart pointeurs (même s'il ne les permet pas aussi bien que C++11), et je préconise déjà leur utilisation (quitte à perdre en perfs en utilisant boost::shared_ptr là où en C++11 on utiliserait std::unique_ptr), mais en plus parce qu'énoncé ainsi la règle fait croire au débutants que si un grep indique 50 new dans un code, un autre grep indiquera 50 delete.

    Mais honnêtement, alors que ne n'ai pu dans mon travail que très récemment utiliser C++11, je ne me souviens pas de la dernière fois où j'ai écrit delete dans du code (sauf dans du débogage ponctuel de code écrit par quelqu'un d'autre que moi).
    Citation Envoyé par koala01 Voir le message

    Ce qui est vrai tant que l'on ne dispose pas des pointeurs intelligents.

    J'espère sincèrement qu'avec C++11, la règle que l'on surinera aux gens deviendra :
    A chaque new doit correspondre un pointeur intelligent équivalent
    Et moi j'espère qu'elle sera : Ne pas utiliser new, et encore moins delete. C'est déjà celle que j'enseigne à mes étudiants. New et delete sont des constructions très bas niveau, contraires au RAII, et en tant que tels à bannir sauf dans les cas rares où l'ont construit une enveloppe RAII par dessus eux.
    Citation Envoyé par koala01 Voir le message
    Mais, cela ne veut absolument pas dire qu'il faille exposer ce pointeur intelligent, pas plus qu'il faille exposer le delete sur le pointeur : Au lieu d'avoir une classe qui appelle explictement delete au niveau du destructeur, tu crées une classe qui manipule en interne le pointeur intelligent qui correspond à tes besoins (qui se chargera de le détruire en temps et en heure) et qui expose les comportements dont tu as besoin
    Je ne parle pas du tout d'exposer quoi que ce soit d'interne à une classe, je parle uniquement de définir une interface de classe de la manière ce qu'il soit aisé d'utiliser cette classe correctement, et malaisé de l’utiliser incorrectement.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  16. #96
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Et tu vas donc "surcharger" l'ensemble de tes prototypes
    Pourquoi surcharger ? Si tu les écris directement comme ceci il n'y a pas de surcharge.

    tu te retrouveras -- fatalement -- avec une classe ou une fonction qui tentera de détruire ou d'accéder à un pointeur qui, par le fait même de la prise de la responsabilité par "autre chose", a de fortes chances d'avoir déjà été invalidé, avec les conséquences que l'on connait tous.
    Si cette fatalité est si grande, tu devrais pouvoir me montrer un exemple de 20 lignes utilisant les règles énoncés (ie celles avec les std::unique_ptr) et qui conduit à une pointeur invalide ?

    Mais la question que je pose est : pourquoi le forcer à utiliser std::move au lieu de n'exposer que des comportements explicites quant au fait qu'il libère un objet de la responsabilité d'un pointeur
    Parce que std::move est justement un comportement explicite qui plus est défini par le standard qui autorise le déplacement de la ressource. std::move est par définition un aide pour appliquer la move semantic, c'est à dire déplacer efficacement une ressource.

    Encore une fois, cela prouve que tu dois avoir une approche globale
    Ça montre surtout que je considère le C++11 comme un "nouveau langage" par rapport au C++03. Ainsi qu'il doive y avoir un niveau d’interfaçage entre les deux n'est pas si étonnant. D'ailleurs, pour les comparaisons avec Qt, je les trouve assez limite : pas de move semantic en C++03, impossible d'avoir des unique_ptr. Le plus proche était boost::scoped_ptr, qui ne conviendrait pas pour des passages en paramètre.

  17. #97
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Là, tu es en train de parler de comment l'objet donne accès à des pointeurs qu'il possède. J'avais l'impression que la discussion initiale était plus de comment transférer à un objet la responsabilité d'un autre.
    Je suis désolé, mais le transfert de responsabilité implique, forcément, qu'il y a interaction entre celui qui cède la responsabilité et celui qui la prend

    En cela, un comportement release() de la part de celui qui la cède est amplement suffisant
    Je n'ai pour ma part jamais dit ça, même en C++03. Déjà car C++03 permet déjà des smart pointeurs (même s'il ne les permet pas aussi bien que C++11), et je préconise déjà leur utilisation (quitte à perdre en perfs en utilisant boost::shared_ptr là où en C++11 on utiliserait std::unique_ptr), mais en plus parce qu'énoncé ainsi la règle fait croire au débutants que si un grep indique 50 new dans un code, un autre grep indiquera 50 delete.
    Elle est très mal exprimée ici, je te l'accorde, mais c'est en gros ce à quoi on en revient à chaque fois .

    Je reconnais très volontiers qu'il y avait des possibilités avant C++11, que les équivalents proposés par boost ne sont pas faits pour les chiens, mais, à partir du moment où, pour une raison ou une autre (qu'elle soit bonne ou mauvaise), on nous dit "désolé, je ne peux pas (je ne veux pas) utiliser boost, C++11 ou que sais-je, on retombera toujours sur quelque chose de très proche de cette règle
    Et moi j'espère qu'elle sera : Ne pas utiliser new, et encore moins delete. C'est déjà celle que j'enseigne à mes étudiants. New et delete sont des constructions très bas niveau, contraires au RAII, et en tant que tels à bannir sauf dans les cas rares où l'ont construit une enveloppe RAII par dessus eux.
    Il est clair que c'est ce vers quoi tendent à nous pousser les pointeurs intelligents, et c'est une excellente chose

    Le problème, c'est que, pour l'instant, new est le seul moyen de centraliser la création d'objets ayant des comportements polymorphes.
    Je ne parle pas du tout d'exposer quoi que ce soit d'interne à une classe, je parle uniquement de définir une interface de classe de la manière ce qu'il soit aisé d'utiliser cette classe correctement, et malaisé de l’utiliser incorrectement.
    Mais est-ce que cela doit forcément passer par le fait d'utiliser unique_ptr dans la signature de la fonction

    A mon sens, non : unique_ptr n'est que le détail d'implémentation qui permet à la classe ou à la fonction d'assumer la responsabilité, rien d'autre.
    Citation Envoyé par Flob90 Voir le message
    Pourquoi surcharger ? Si tu les écris directement comme ceci il n'y a pas de surcharge.
    J'utilisais le terme "surcharger" au sens propre du terme, et non au sens de surcharge du point de vue C++ (ne me fais pas croire que tu ne l'avais pas remarqué, tu descendrais dans mon estime )
    Si cette fatalité est si grande, tu devrais pouvoir me montrer un exemple de 20 lignes utilisant les règles énoncés (ie celles avec les std::unique_ptr) et qui conduit à une pointeur invalide ?
    Si je te montre un exemple de vingt lignes, tu me taxeras encore de je ne sais pas quoi.

    Considère simplement le fait que, si la responsabilité du pointeur n'est pas prise dés le départ par "quelque chose", il est très facile d'arriver à un point où la responsabilité peut avoir été prise ... ou non, en fonction du trajet qu'aura suivi le pointeur et ce du seul fait des possibilités offertes par le langage (l'héritage avec la possibilité des comportements polymorphes, création de foncteurs, l'appel de fonction "en cascade", la surcharge des fonctions, la possibilité d'avoir des valeurs par défaut pour les arguments, j'en passe et de meilleur).

    C'est, bien sur, des situations qui doivent être évitées comme la peste, je ne dis certainement pas le contraire!

    Mais ce sont des situations auxquelles tu risques parfaitement d'être confronté si tu n'envisages pas la gestion de la responsabilité d'un pointeur de manière globale.
    Parce que std::move est justement un comportement explicite qui plus est défini par le standard qui autorise le déplacement de la ressource. std::move est par définition un aide pour appliquer la move semantic, c'est à dire déplacer efficacement une ressource.
    std::move est plus un moyen trouvé par C++11 d'arriver à tirer les marrons du feu sans se brûler les doigts et de manière élégante.

    Je ne remet aucunement les choix en cause (bien au contraire, je les approuve), mais il faut se rendre compte que le besoin que l'on peut éprouver d'avoir std::move n'est en somme que la conséquence logique de certaines décisions (que j'approuve entièrement) logiques et dont le point de départ a été une réflexion (tout à fait cohérente au demeurant) proche de "ce serait franchement pas mal s'il y avait moyen de prendre une référence sur une rvalue".

    Ne me faites maintenant pas dire ce que je n'ai pas dit : je ne prétend absolument pas remettre les choix qui ont été faits en question, car je suis en plein accord avec eux.

    Mais, de mon point de vue, tout ce qui a trait aux rvalue-reference et à la sémantique de mouvement représente un problème d'une complexité telle que, s'il y a moyen de s'en passer, on ne s'en portera que mieux.

    Bien sur, il y aura des cas dans lesquels nous n'auront pas d'autre choix que de passer par les rvalue-reference et la sémantique de mouvement, mais ce n'est à mon sens pas une raison pour se mettre dans une situation dans laquelle nous serons forcé d'y recourir.

    Cela ne revient ni plus ni moins à se taper sur la tête avec un marteau en se disant que cela fait tellement de bien quand ca s'arrête
    Ça montre surtout que je considère le C++11 comme un "nouveau langage" par rapport au C++03. Ainsi qu'il doive y avoir un niveau d’interfaçage entre les deux n'est pas si étonnant. D'ailleurs, pour les comparaisons avec Qt, je les trouve assez limite : pas de move semantic en C++03, impossible d'avoir des unique_ptr. Le plus proche était boost::scoped_ptr, qui ne conviendrait pas pour des passages en paramètre.
    C++11 n'est pas un "nouveau" langage!

    C'est l'évolution "naturelle" d'un langage existant, autrement, il ne se serait pas appelé C++!

    C'est d'autant plus vrai que, contrairement à d'autres langages, il veille à casser "un minimum de choses" par rapport à l'existant

    C++11 vient avec son lot de nouvelles possibilités et de nouvelles fonctionnalités et c'était nécessaire.

    je suis tout à fait d'accord sur le fait que nous aurions très certainement tord de nous priver des nouvelles possibilités.

    Mais, comme toute technique, il faut prendre le temps de se l'approprier, d'en comprendre les tenants et les aboutissants, de se faire une idée précise des problèmes qu'elle permet de résoudre et des cas dans lesquels leur utilisation ne fera que rajouter de la complexité inutile.

    En un mot, il ne sert à rien de se dire "wouah, génial, on a les rvalue-reference et la sémantique de mouvement, utilisons les à toutes les sauces", il faut prendre le temps de comprendre vraiment quand ces deux notions sont réellement utiles et présente un réel intérêt.

    Et quand je vois la complexité du problème associé à ces deux notions, je ne peux m'empêcher de penser que plus il y aura moyen d'éviter que l'utilisateur (c'est à dire moi même) ne doive commencer à jouer avec elles (autrement dit : plus il y aura moyen de garder le fait que je les manipule en tant que développeur comme étant un détail d'implémentation), mieux l'utilisateur (c'est à dire moi meme ) s'en portera.

    Je ne dis pas qu'il ne faut pas s'intéresser au problème, très loin de là.

    Je dis que cet aspect mérite très amplement d'être utilisé de manière transparente pour celui qui utilise les classes et les fonctions que je mettrai à sa disposition (même si je dois être le seul à les utiliser)
    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

  18. #98
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut
    bonsoir,

    je ne sais pas si ça va vous aider à trancher,
    mais j'ai lu un peu votre discussion, et je suis plutôt un bon développeur, c'est d'ailleurs mon boulot. Je n'ai jamais utilisé de Rvalue reference donc j'ai dû regarder un peu ce que c'était, et en gros j'ai mis 4 heures pour comprendre cette histoire (unique_ptr + Rvalue reference + std::move), et encore je ne suis pas sûr d'avoir tout cerné.

    Donc si vous l'utilisez sur un projet, sachez que les bons développeurs mettront 4 heure à en comprendre les subtilités, et les autres n'y comprendront rien, ce qui fait quand même pas mal d'heures juste pour un petit pointeur de rien du tout !

  19. #99
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 113
    Points : 32 960
    Points
    32 960
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par acx01b Voir le message
    bonsoir,

    je ne sais pas si ça va vous aider à trancher,
    mais j'ai lu un peu votre discussion, et je suis plutôt un bon développeur, c'est d'ailleurs mon boulot. Je n'ai jamais utilisé de Rvalue reference donc j'ai dû regarder un peu ce que c'était, et en gros j'ai mis 4 heures pour comprendre cette histoire (unique_ptr + Rvalue reference + std::move), et encore je ne suis pas sûr d'avoir tout cerné.

    Donc si vous l'utilisez sur un projet, sachez que les bons développeurs mettront 4 heure à en comprendre les subtilités, et les autres n'y comprendront rien, ce qui fait quand même pas mal d'heures juste pour un petit pointeur de rien du tout !
    En fait ça dépend surtout de quel intérêt tu portes au C++11 et ses évolutions.
    Pour ma part, j'ai pas énormément suivi tout ça, surtout parce qu'au boulot on ne l'utilise pas encore. Mais de loin, la seule grosse évolution que j'apprécie ce sont les variadic template. Et là encore, utilisant visual studio, je n'en ai pas encore utilisé.
    Cela dit, il s'agit juste de nouveaux concepts, donc à connaître. Après on peut légitimer sur l'appelation de "bon développeur", quand en 2013, bientôt 2014 on ne connaît pas même le nom d'une nouveauté de 2011. Mais c'est totalement subjectif.

    Pour ma part, je n'ai jamais été friand des pointeurs intelligents, c'est pratique, mais le principe ne me plait pas (enfin les shared_ptr particulièrement).
    Pour ce seul aspect, je serai plus partisan du pointeur nu, et de documenter la méthode.
    On n'est de toutes jamais à l'abri de quelqu'un qui fait n'importe quoi avec notre code, donc cet argument en faveur du unique_ptr me semble bancal.
    Et être conscient des problèmes de responsabilité, que beaucoup de développeurs ignorent encore
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  20. #100
    Membre expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Points : 3 892
    Points
    3 892
    Par défaut
    Je pense pour ma part que ceux qui s'y connaissent le plus sont encore ceux qui passent le plus de temps à en discuter interminablement .

    En cela, un comportement release() de la part de celui qui la cède est amplement suffisant
    Un comportement de reinterpret_cast<void*> pour utiliser l'interface en void* si on veut faire le parallèle ?

    (ne me fais pas croire que tu ne l'avais pas remarqué, tu descendrais dans mon estime )
    Ce mot est suffisamment ambigu dans ce contexte, il me semble avoir d'ailleurs eu quelques discussions avec Flob à ce sujet (ou en tout cas, si ce n'est j'en avais l'intention, pour surcharger entre & et &&, bref c'est pas le sujet )

    A mon sens, non : unique_ptr n'est que le détail d'implémentation qui permet à la classe ou à la fonction d'assumer la responsabilité, rien d'autre.
    C'est vrai, on devrait se contenter de auto f(var a, var b, var c) pour nos signatures... Je pense que je ne vais jamais pouvoir m'accorder avec toi sur le fait qu'une signature d'une fonction fait sa documentation pour une très large partie... et a le mérite d'être lisible par l'humain et le compilateur .

    Mais, de mon point de vue, tout ce qui a trait aux rvalue-reference et à la sémantique de mouvement représente un problème d'une complexité telle que, s'il y a moyen de s'en passer, on ne s'en portera que mieux.
    Mon code n'a jamais été si propre, lisible, et surtout sans bug de mémoire ! depuis que je manie la sémantique de mouvement. Sincèrement cette feature bien qu'imparfaite à mes yeux est un réel progrès.
    J'y mettrais toutefois un bémol, les && explicites me sortent par les yeux et je les fuis allègrement (Murphy m'a attendu au tournant à plusieurs reprises). Et j'ajouterai que je me porte très bien (mon code aussi ) sans les utiliser.

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