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 :

Le draft de la prochaine norme C++14 est disponible !


Sujet :

C++

  1. #41
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Citation Envoyé par Klaim Voir le message
    Ya aussi std::dynarray?
    Non, les dynarray sont dans un autre draft (N3662)

  2. #42
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Tiens, au fait, il y a une proposition pour créer un pointeur intelligent équivalent de weak_ptr pour unique_ptr ?

    EDIT : ou alors, ça n'a pas de sens, parce que j'utilise mal unique_ptr... voir mon message en dessous

  3. #43
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Il me semble qu'il y a eu des discussions a ce propos. Pour l'instant il est preconise d'utiliser un pointeur nu pour les pointeurs qui n'ont pas d'ownership ( je ne sais pas comment traduire ce mot dans notre cas...).

    Je sais pas si ca vaudrait le coup d'avoir un pointeur qui fait la meme chose mais serait explicitement nome... je me dis que l'avantage existe mais est pas bien grand.

  4. #44
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Mais un pointeur nu n'est pas tout à fait équivalent...s'il coopère avec le smart-pointer propriétaire de la référence, un weak_ptr peut par exemple offrir le moyen de tester si la référence est toujours valable.

  5. #45
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Je vais préciser mon EDIT (n"hésitez pas à splitter la discussion si nécessaire)

    Remarque préalable : je n'ai pas retrouvé les anciennes discussions sur l'équivalent de weak_ptr pour unique_ptr.

    Problème de la responsabilité. C'est une question régulièrement débattue (sur le chat avec germinolegrand par exemple), voir par exemple l'article d'Emmanuel Deloget : Les devs C++ ne sont pas partageur.

    Avec unique_ptr, il faut se poser la question de qui a la responsabilité. Avec shred_ptr, on peut ne pas se préoccuper de qui a la responsabilité. Faut juste faire attention aux références circulaires, mais rien de compliqué.

    Validité. C'était mon raison initiale pour un équivalent de weak pour unique. weak proposer en effet expired, qui permet de tester si l'objet est encore valide :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class WorkOnWeak {
        weak_ptr<T> wp;
    public:
        WorkOnWeak(shared_ptr<T> sp) : wp(sp) {}
        void doWork() { 
            if (!wp.expired())
                use_weak(wp);
        }
    };
    Avec unique/T*, on peut avoir un problème, puisque l'on ne peut pas tester si l'objet est encore valide :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class WorkOnPointer {
        T* p;
    public:
        WorkOnPointer(unique_ptr<T> up) : p(up.get()) {}
        void doWork() { 
            if (!p) // indéterminé
                use_pointer(p);
        }
    };
    Donc l'idée serait d'avoir une classe encapsulant le weak_unique_ptr (désolé, j'ai pas trouvé de nom plus pertinent) :
    1. meilleure sémantique (en particulier avec le code ancien, pour indiquer clairement que l'on a pas la responsabilité et éviter que quelqu'un appel un delete sur l'objet géré par unique)
    2. pouvoir tester si l'objet est valide

    Le raisonnement se pose donc en termes de qui à la responsabilité de la destruction des objets et s'ils sont détruits avant de les utiliser.

    Ok, ça, c'était mon raisonnement pour justifier le weak_unique_ptr. Mais ça c'était avant mon EDIT...

    Validité "étendue". Le départ de ma réflexion est l'utilisation de weak_ptr. En fait, quand on regarde le codes d'exemple de cppreference, on utilise pas expired, mais lock.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class WorkOnWeak {
        weak_ptr<T> wp;
    public:
        WorkOnWeak(shared_ptr<T> sp) : wp(sp) {}
        void doWork() { 
            if (auto sp = wp.lock())
                use_shared(sp);
        }
    };
    L'idée est que pour travailler sur un objet, il ne faut pas simplement vérifier son existence préalable, mais garantir que l'objet existe durant toute le durée de son utilisation (par exemple dans un contexte multithreads... et la lecture des GOTW 6 sur const/mutable montre qu'il faut penser en ces termes en C++11).

    Jusque là, rien d'exceptionnel et weak_ptr a été conçu dans ce sens : on ne peut pas déréférencer un weak_ptr, il faut passer par un shared.

    Revenons maintenant à unique_ptr. Il a été créé pour être un pointeur intelligent léger, sans compteur de référence. Ce qui revient à dire qu'il a la responsabilité de la destruction et qu'il n'a pas à se préoccuper si d'autre l'utilise ou non. En gros, c'est un égoïste "Je te prête pas mon jouet, si tu en veux un, tu vas t'en acheter ou tu attends que j'en veux plus".
    La création d'un weak_unique_ptr ne résout pas ce problème. On aura aucune garantie que l'objet n'est pas détruit pendant son utilisation. On fonce dans le mur.

    Donc, si on raisonne en termes de garantie de validité des objets, dans ce cas, la création d'un weak_unique_ptr n'est pas une bonne chose. Si on récupère le unique par move, soit on fait rien. Mais on travaille pas avec un T* ou weak_unique_ptr.
    Ce qui revient à dire que dans de nombreux pattern (par exemple une collection), il ne faut pas utiliser un unique (en partant du principe que c'est la collection qui gère la durée de vie des objets), mais des shared (pour que les utilisateurs des objets aient une garantie de leurs validités)
    On pourrait à la rigueur utiliser unique dans un collection qui auraient la même durée de vie que le programme et qui ne supprime pas d'objet... mais c'est pas ce que l'on pourrait appeler de la gestion fine de la mémoire

    Bref, en conclusion, pas sur qu'il faut ajouter ça dans la norme en fait

  6. #46
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    ce n'est peut-être pas le bon endroit, mais je voudrais en profiter pour émettre une critique sur le mot-clé auto.
    Je suis en train d'analyser un code qui abuse des templates, avec des auto de partout, et c'est un enfer pour comprendre ce qu'il se passe. Après 2 niveaux d'appels de fonction, il est quasiment impossible de savoir sur quels types on est en train de travailler, et donc quels objets le code est en train de manipuler.

    Ajoutez à cela un contexte difficile (pas de commentaires, pas de doc, une mauvaise conception, et un programme compliqué à exécuter en pas à pas), et on est au bord du nervous breakdown!

    Si j'avais des types bien définis à la place des auto, ce serait déjà un gros plus dans mon cas.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  7. #47
    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 r0d Voir le message
    ce n'est peut-être pas le bon endroit, mais je voudrais en profiter pour émettre une critique sur le mot-clé auto.
    Je suis en train d'analyser un code qui abuse des templates, avec des auto de partout, et c'est un enfer pour comprendre ce qu'il se passe. Après 2 niveaux d'appels de fonction, il est quasiment impossible de savoir sur quels types on est en train de travailler, et donc quels objets le code est en train de manipuler.

    Ajoutez à cela un contexte difficile (pas de commentaires, pas de doc, une mauvaise conception, et un programme compliqué à exécuter en pas à pas), et on est au bord du nervous breakdown!

    Si j'avais des types bien définis à la place des auto, ce serait déjà un gros plus dans mon cas.
    Je crois que ce qu'il manque en ce qui concerne auto, c'est surtout un peu de recul afin d'être en mesure de se "discipliner" comme on a pu le faire pour différentes méthodes.

    Car, soyons honnêtes, s'il faut commencer à se coltiner de std::macollection<MonTypeAuNomFarfelu>::const_iterator à tour de bras, tant que l'on reste dans la classe qui utilise la collection, auto a quand meme le mérite de rendre le code bien plus agréable et facile à comprendre.

    Par contre, je reconnais que si l'on passe par cinq fonctions libres, trois visiteurs, quatre foncteur et 9 accesseurs pour obtenir la donnée qui est utilisée par une donnée utilisée par...(bon, ben, tu vois le genre ) à laquelle on n'aurait jamais du pouvoir accéder, il est clair que le mot clé auto a beau faciliter l'écriture, mais que pour le débuggage (ou meme simplement pour comprendre le code)...
    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

  8. #48
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    C'est pour ça que je suis un fervent partisan des typedef.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  9. #49
    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
    Citation Envoyé par gbdivers Voir le message
    Je vais préciser mon EDIT (n"hésitez pas à splitter la discussion si nécessaire)

    Remarque préalable : je n'ai pas retrouvé les anciennes discussions sur l'équivalent de weak_ptr pour unique_ptr.

    Validité. C'était mon raison initiale pour un équivalent de weak pour unique. weak proposer en effet expired, qui permet de tester si l'objet est encore valide
    [...]
    Ce qui revient à dire que dans de nombreux pattern (par exemple une collection), il ne faut pas utiliser un unique (en partant du principe que c'est la collection qui gère la durée de vie des objets), mais des shared (pour que les utilisateurs des objets aient une garantie de leurs validités)
    On pourrait à la rigueur utiliser unique dans un collection qui auraient la même durée de vie que le programme et qui ne supprime pas d'objet... mais c'est pas ce que l'on pourrait appeler de la gestion fine de la mémoire

    Bref, en conclusion, pas sur qu'il faut ajouter ça dans la norme en fait
    J'ai essayé de défendre l'idée à Bristol, mais je n'ai eu qu'un accord mou poli... En fait une telle classe aurait plusieurs intérêts :
    - Documentation du code (le cas est arrivé avec la proposition sur les allocateurs polymorphes, où l'on passe un allocator*, et où des gens se sont posés des questions sur la responsabilité de l'objet)
    - Éviter des fausses manips (delete sur un tel objet)
    - Vérifications, mais c'est très secondaires. Pour moi, si vérifications il y a sur un tel objet, ce n'est pas fonctionnel comme les weak_ptr, mais à des fins de debug uniquement, sous forme d'assert. Et ça a effectivement un coût qu'on ne veut pas faire payer à unique_ptr... du moins pas en mode optimisé. En mode debug, de n'est pas très grave si le coût est augmenté, mais que je peux me rendre compte que mes préconditions sur la validité de mes objets sont mauvaises.
    - Peut être possibilité pour des outils d'analyse statique de code de profiter de la sementique mieux définie pour trouver des problèmes.
    - J'ai l'impression que j'en oublie...
    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.

  10. #50
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    - Éviter des fausses manips (delete sur un tel objet)
    Ca c'est une tres tres bonne raison!

  11. #51
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    J'ai essayé de défendre l'idée à Bristol, mais je n'ai eu qu'un accord mou poli... En fait une telle classe aurait plusieurs intérêts :
    - Documentation du code (le cas est arrivé avec la proposition sur les allocateurs polymorphes, où l'on passe un allocator*, et où des gens se sont posés des questions sur la responsabilité de l'objet)
    - Éviter des fausses manips (delete sur un tel objet)
    - Vérifications, mais c'est très secondaires. Pour moi, si vérifications il y a sur un tel objet, ce n'est pas fonctionnel comme les weak_ptr, mais à des fins de debug uniquement, sous forme d'assert. Et ça a effectivement un coût qu'on ne veut pas faire payer à unique_ptr... du moins pas en mode optimisé. En mode debug, de n'est pas très grave si le coût est augmenté, mais que je peux me rendre compte que mes préconditions sur la validité de mes objets sont mauvaises.
    - Peut être possibilité pour des outils d'analyse statique de code de profiter de la sementique mieux définie pour trouver des problèmes.
    - J'ai l'impression que j'en oublie...
    Oui, c'est le côté sémantique dont j'ai parlé. Je suis d'accord sur ces points : il est préférable d'avoir le couple unique_ptr/weak_unique_ptr que unique_ptr/T*.

    Mais mon interrogation portait sur un autre point : n'est-il pas dangereux d'utiliser un objet dont à n'a pas le contrôle de sa durée de vie. Donc le choix est unique_ptr/autre_chose vs unique_ptr seul.
    J'ai l'impression que l'on peut garantir la validité avant l'utilisation de l'objet, mais pas pendant son utilisation. Et donc qu'il ne faut à aucun moment utiliser de weak_unique

    Cela pourrait être résolu par l'utilisation de smart ptr thread safe. Ça n'a pas été prévu dans le futur ? (avec un paramètre template de police pour éviter le surcoût quand on utilise pas)

    Sinon, tu n'as pas essayé de proposer un weak_unique dans boost, pour voir l'utilisation en pratique ?

  12. #52
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Le cas typique ou j'espose des pointeurs, et qui est courant dans le jv c'est quand l'objet en question fais partie d'un pool. On le fournis, mais c'est la factory qui detiens le pool qui decide quand l'objet meurs. L'utilisateur est oblige de partir du principe que l'objet est valide tans que le pool est vivant.

    Recement je me suis retrouve avec une variante de ce cas mais dans une contexte multithreade ou j'ai besoin de plus de garanties. J'ai un systeme avec une interface thread-safe. Ce systeme contiens un pool par type d'objet gere (il y a une fonction pour ajouter un nouveau type ce qui cree un nouveau pool). L'interface fournis de quoi creer ou detruire les dits objets, ainsi que d'ajouter ou d'enlever des objets heritant d'une interface specifique dont une fonction virtuelle d'update est appele sur chacuns des objets d'un type donne (de maniere a ce qu'il y ait une sorte de boucle d'update sur un thread associe au system). Quand on appelle l'update du systeme, tout se fait sur le thread qui appelle la fonction d'update, donc tout est mis a jour ensemble. En revanche, les fonctions de creation et d'acces aux objets dans les pools fournissent toutes un acces vers un moniteur qui ne permet d'acceder a l'objet demande que part des objets-fonctions, de maniere a les ajouter sur une queue de taches qui est executee a l'update.

    Je me suis retrouve a exposer deux fonctions pour creer des objets dans le pool: une pour creer sans recuperer l'ownership, une ou on la recupere. La premiere sert a creer des objets autonomes (pas besoin d'y acceder depuis l'exterieur, l'update normale suffit) du coup on ne retourne rien et du coup l'objet ne sera detruit qu'a la destruction du pool. La seconde fonction par contre retourne un unique_ptr<Monitor<MonObjet>,SpecialDeleter> de maniere a ce que l'utilisateur decide comment gerer la vie de l'objet. Ici le SpecialDeleter contiens un weak_ptr<Pool<MonObjet>> qui est utilise a la destruction du unique_ptr (ou du shared_ptr si il a ete passe dedans). Du coup j'utilise les fonctions de destruction du pool si il est toujours vivant (sinon l'objet doit etre mort aussi de toutes facons).

    Tout ca pour dire qu'au final je me retrouve quasimment qu'avec des unique_ptr ou des shared_ptr.

    Un autre cas ou j'utilise des pointeurs natifs c'est quand j'ai besoin de lister des objets dans un vecteur sans les detenir, juste pour faire une operation qui implique par exemple un tri.

  13. #53
    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
    Alors, et puisque la perche est si poliment tendue, je vais répondre à propos de auto et typedef (brr... using !), et embrayer sur la réflexion de gbdivers à propos des unique_ptr (attention, je sens que ça va être un sujet à part entière comme il le dit lui-même).

    Pour ma part, en ce qui concerne auto, si j'en use et j'en abuse dans l'implémentation, en revanche je le bannis de la déclaration, et ce au profit de using qui offre la possibilité d'une meilleure sémantique, tout en offrant une bonne généricité.

    Ainsi que je l'ai déjà dit plus haut (je crois ?), si vous tenez à vous faire insulter, mettez donc des auto de partout dans vos interface .

    Pour le weak_unique_ptr, c'est le besoin de tester la validité qui est un faux besoin et la clé de tout le problème. Pourquoi tester la validité d'une référence ? Cela a-t-il un sens ? Non, si vous disposez encore d'un accès à un objet c'est qu'il est valide. C'est au responsable de l'objet (ou à l'objet lui-même) que revient la tâche de s'assurer que lors de sa destruction il ne sera plus référencé ailleurs. Du coup, l'utilisation d'un objet peut se faire totalement indépendamment du responsable qui peut donc être un unique_ptr, un conteneur, ou tout bêtement la pile, mais ça regarde le responsable de l'objet, et non son utilisateur qui se contente parfaitement d'une référence.

    Il faut donc se poser la question : mais quelle est l'utilité d'un unique_ptr ?

    Le conteneur vector (contrairement à list par exemple) a besoin d'un objet déplaçable (ou copiable à défaut, mais c'est rarement le comportement souhaité), c'est déjà une première utilité : std::vector<std::unique_ptr<T>> vous permet de stocker dans un conteneur dynamique un objet qui n'est pas déplaçable. Cette première utilité est principalement pratique lorsque l'on manipule des objets donc la classe a été créée pour du C++03 (typiquement si la classe est non-copiable explicitement ce qui est une pratique courante en C++03 -- en déclarant en réalité qu'elle est copiable mais seulement en privé ce qui est en fait une sorte de hack pour le même résultat, C++11 précise qu'elle est implicitement non-déplaçable, même dans le cas où ça ne poserait pas de problème de la déplacer).

    Si vous instanciez un objet sur la pile, ou dans un conteneur, vous pouvez utiliser des références (j'emploie le terme référence pour signifier référence ou pointeur nu, il n'y a pas de différence sémantique dans le contexte qui nous intéresse) sur cet objet, ça ne pose pas de problème particulier. Par contre, si vous souhaitez stocker une référence, alors là vous allez avoir des problèmes : dès le moment où l'objet sera déplacé, votre référence est invalidée. En effet : quand vous et moi nous déplaçons, nous changeons d'adresse ; les objets font pareil ! C'est là qu'intervient la deuxième utilité d'un unique_ptr<A> qui vous permet de ne plus avoir à déplacer l'objet -- seulement le unique_ptr, ce qui vous garantie que les références sur cet objet seront toujours valides, magnifique nous avons une solution qui nous permet d'apporter des modifications à la méthode de stockage et de responsabilité d'un objet sans toucher au code qui utilise cet objet via une référence.

    Une troisième utilité du unique_ptr c'est lorsque vous souhaitez une responsabilité unique et polymorphe.

    Maintenant, si le besoin en weak (qui n'est pas systématique, souvent les références sont tout à fait adaptées) pose problème, c'est parce pour ce besoin les shared_ptr en font trop, et les unique_ptr pas assez.

    Le constat est simple, il manque des pointeurs intelligents. Des pointeurs responsables autant que des weaks. Analysons la situation :

    0. Si la responsabilité de votre objet est situé en un seul point et si les références sur votre objet sont seulement consommées, nul besoin d'un pointeur intelligent. Pas de polymorphisme de stockage (solution 2 le cas échéant). L'objet est déplaçable vers toute autre solution.

    1. Si votre objet est immobile (comprendre il ne sera pas déplacé) et que la responsabilité se situe en un seul point, nul besoin de pointeur intelligent. Les références peuvent être stockées. Pas de polymorphisme de stockage (solution 2 le cas échéant). Pas de possibilité d'évolution.

    2. Si vous voulez pouvoir déplacer un objet dont la responsabilité se situe en un seul point sans invalider les références stockées, unique_ptr est parfaitement capable et tout à fait adapté. Cette solution permet de déplacer la responsabilité de l'objet sans problème vers tout autre solution qui assure au moins la continuité de validité des références lors du déplacement.

    3. Si vous avez un objet dont la responsabilité se situe en un seul point mais que votre objet peut être détruit avant les références, les références doivent devenir des weaks. Pas de solution disponible actuellement (sauf un unique shared_ptr (!) couplé à des weak_ptr, mais il en fait trop que ce soit sémantiquement ou techniquement). La possibilité de déplacement de la responsabilité vers une autre solution ou la même solution serait souhaitable.

    4. Si vous avez un objet dont la responsabilité est partagée entre plusieurs responsables, et qui doit être détruit lorsque le premier des responsables provoque sa destruction, les références doivent devenir des weaks, potentiellement avec la même interface que ceux de la solution 3. Pas de solution disponible actuellement.

    5. Si vous avez un objet dont la responsabilité est partagée et que votre objet doit être détruit lorsque le dernier des responsables est détruit, alors le couple shared_ptr/weak_ptr a tout pour plaire. Pas de possibilité d'évolution.

    J'ai la nette impression d'avoir oublié au moins un cas. N'hésitez pas à compléter s'il vous apparaît qu'il en manque un

  14. #54
    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
    En ce qui concerne auto, le problème qui est soulevé, à savoir (pour résumer) qu'on ne sait plus le type de l'objet dans certain cas, et donc par extension ce qu'on peut en faire.

    A l'heure actuelle je trouve aussi que c'est vrai et qu'un des seuls palliatifs est de documenter en espérant que l'utilisateur prenne le temps de lire la documentation et de voir les concepts que doivent respecter les retours des fonctions utilisées. Et commente ses implémentations si il veut faciliter sa relecture et savoir ce qu'il peut faire avec quoi.

    En effet, il est inutile de connaitre exactement le type d'un objet, tout ce qui est intéressant c'est de savoir ce qu'on peut faire avec cette objet. Et c'est déjà la philosophie en oeuvre quand on fait un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector<MonType>::iterator
    On ne sait absolument pas ce qu'est ce type, tout ce qu'on sait c'est qu'il respect le concept d'itérateur (par documentation d'ailleurs, la norme dans ce cas).

    Par contre les choses pourraient changer avec l'introduction des concepts en C++. Je ne sais pas où en est le comité sur ce point, mais si la possibilité d'indiquer un concept au type de retour d'une fonction tout en profitant de l'inférence (auto), alors l'abus d'auto n'est plus un problème. Pour les développeurs qui connaissent, on peut faire un parallèle avec les classes de types d'Haskell et la possibilité de les indiquer dans la "signature".

    Il reste la question de l'abus des auto dans les implémentations pour favoriser la relecture (ie ne pas devoir consulter les signatures, ou des commentaires). Il faudrait aussi la possibilité de profiter de l'inférence à la déclaration avec définition sous contrainte d'une compatibilité de concept. (Je ne peux pas faire le parallèle avec Haskell ici, par nature même du langage).

  15. #55
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Citation Envoyé par germinolegrand Voir le message
    Pour ma part, en ce qui concerne auto, si j'en use et j'en abuse dans l'implémentation, en revanche je le bannis de la déclaration, et ce au profit de using qui offre la possibilité d'une meilleure sémantique, tout en offrant une bonne généricité.

    Ainsi que je l'ai déjà dit plus haut (je crois ?), si vous tenez à vous faire insulter, mettez donc des auto de partout dans vos interface .
    Pareil.

    2. Si vous voulez pouvoir déplacer un objet dont la responsabilité se situe en un seul point sans invalider les références stockées, unique_ptr est parfaitement capable et tout à fait adapté. Cette solution permet de déplacer la responsabilité de l'objet sans problème vers tout autre solution qui assure au moins la continuité de validité des références lors du déplacement.
    Note qu'il y a une variante a ce cas (qu'on utilise par exemple dans certaines implementations de moteurs de jeux): on veut donc pouvoir deplacer l'objet physiquement mais l'objet appartient a un pool, donc fixe, mais doit quand meme etre reference par du code exterieur. Dans ce cas un Id quelconque feras l'affaire (mais selon les cas l'implementation de l'id peut largement differer).

    3. Si vous avez un objet dont la responsabilité se situe en un seul point mais que votre objet peut être détruit avant les références, les références doivent devenir des weaks. Pas de solution disponible actuellement (sauf un unique shared_ptr (!) couplé à des weak_ptr, mais il en fait trop que ce soit sémantiquement ou techniquement). La possibilité de déplacement de la responsabilité vers une autre solution ou la même solution serait souhaitable.
    C'est ce cas la qui m'interpelle le plus. Effectivement un unique shared_ptr et multiple weak_ptr me semble la bonne solution...(sauf si tu comptes deplacer l'objet physiquement).

    Au final le souci avec shared_ptr c'est qu'on paye le thread-safety meme dans les cas ou il n'y a qu'un seul thread qui utilise le pointeur.

    4. Si vous avez un objet dont la responsabilité est partagée entre plusieurs responsables, et qui doit être détruit lorsque le premier des responsables provoque sa destruction, les références doivent devenir des weaks, potentiellement avec la même interface que ceux de la solution 3. Pas de solution disponible actuellement.
    Interessant... ca ressemble a plusieurs cas que j'ai en fait, ou au final je suis oblige de faire en sortes que l'un des responsables utilise une interface particuliere pour detruire l'objet de maniere a ce que les references (dans mon cas des Id speciaux) soient notifies du changement.

    Mais la plupart des implementations possibles sont assez lourdes je trouve. C'est pas similaire aux shared_future?

    5. Si vous avez un objet dont la responsabilité est partagée et que votre objet doit être détruit lorsque le dernier des responsables est détruit, alors le couple shared_ptr/weak_ptr a tout pour plaire. Pas de possibilité d'évolution.
    Je ne suis pas sur de comprendre ce que tu veux dire par la? Qu'il faut un type moins lourd qui puisse etre "upgrade" vers shared_ptr si le besoin se fait?

  16. #56
    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
    Citation Envoyé par germinolegrand Voir le message
    0. Si la responsabilité de votre objet est situé en un seul point et si les références sur votre objet sont seulement consommées, nul besoin d'un pointeur intelligent. Pas de polymorphisme de stockage (solution 2 le cas échéant). L'objet est déplaçable vers toute autre solution.
    Je ne suis pas trop dans l'état d'esprit de répondre au reste maintenant, mais sur ce point, je ne suis pas forcément d'accord : Même si la responsabilité est en un seul point, unique_ptr peut simplifier l'écriture de ce point par rapport à un pointeur nu.
    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.

  17. #57
    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
    Citation Envoyé par JolyLoic Voir le message
    Je ne suis pas trop dans l'état d'esprit de répondre au reste maintenant, mais sur ce point, je ne suis pas forcément d'accord : Même si la responsabilité est en un seul point, unique_ptr peut simplifier l'écriture de ce point par rapport à un pointeur nu.
    Je n'envisage en aucun cas l'utilisation d'un pointeur nu comme responsable, mais seulement dans les références (un pointeur nu ou une référence, pas de différence sauf pour un stockage dans un conteneur).

    Les solutions 0 et 1 c'est déclarer un objet sans aucun pointeur pour le contenir, il est régi par le scope tout simplement.

  18. #58
    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
    Citation Envoyé par Klaim Voir le message
    Au final le souci avec shared_ptr c'est qu'on paye le thread-safety meme dans les cas ou il n'y a qu'un seul thread qui utilise le pointeur.
    Tu as une mesure de cette baise de performance ? Parce qu'il me semble que les shared_ptr en MT, ca se fait avec du lock free, du coup l'impact sur les performances, j'ai un petit doute ... Que les shared_ptr ai un coût comparé à un unique_ptr à cause du compteur, je le comprend (même si il me semble que les bench montre que le coût n'est pas si élevé), et si le caractère MT a un coût, je pense qu'il est négligeable comparé au coût du compteur.

  19. #59
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    Tu as une mesure de cette baise de performance ? Parce qu'il me semble que les shared_ptr en MT, ca se fait avec du lock free, du coup l'impact sur les performances, j'ai un petit doute ... Que les shared_ptr ai un coût comparé à un unique_ptr à cause du compteur, je le comprend (même si il me semble que les bench montre que le coût n'est pas si élevé), et si le caractère MT a un coût, je pense qu'il est négligeable comparé au coût du compteur.
    Je n'ai pas de mesure, c'est ce que repetent Herb Sutter et ses amis. Personnellement ca ne me gene pas d'utiliser shared_ptr quand j'en sent le besoin parceque je suis encore loin d'une phase d'optimization sur mes travaux actuels.

    Cela dis meme si lockfree, ca dois avoir un impact visible a la destruction quand ya beaucoup de shared et qu'ils sont tous detruits a peu pret en meme temps. Hors les ralentissements a la destructions c'est un peu ce qui nous fais hurler quand on a besoin de performances previsible.

  20. #60
    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
    @Klaim: Tu pourrais donner une référence, un lien, un article, une discussion ? Je suppose qu'il ne fait pas que dire "c'est coûteux" mais qu'il explique le pourquoi, ce qui m’intéresse.

Discussions similaires

  1. la norme C90 - Elle est ou?
    Par wee_bee dans le forum C
    Réponses: 3
    Dernier message: 16/06/2010, 23h01
  2. obtenir le prochain ID en mode auto-increment
    Par arnololo dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 03/12/2003, 17h43
  3. wxWindows et DevC++ : taille de l'exe énorme !
    Par ovh dans le forum Dev-C++
    Réponses: 7
    Dernier message: 19/11/2003, 17h01
  4. Normes EDI
    Par f-demu01 dans le forum Langages de programmation
    Réponses: 2
    Dernier message: 14/03/2003, 08h22

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