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 :

Pointeurs intelligents vs. pointeurs bruts


Sujet :

C++

  1. #61
    screetch
    Invité(e)
    Par défaut
    pour la guerre de religion reference/pointeur j'ai dit plus haut que:
    * pointeur c'est plutot pour les entités
    * référence c'est plutot pour les valeurs

    je n'ai vu personne commenter mais je me demande quand même ce que vous en pensez.

  2. #62
    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 screetch Voir le message
    pour la guerre de religion reference/pointeur j'ai dit plus haut que:
    * pointeur c'est plutot pour les entités
    * référence c'est plutot pour les valeurs

    je n'ai vu personne commenter mais je me demande quand même ce que vous en pensez.
    C'est quoi pour toi entités et valeurs?

  3. #63

  4. #64
    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
    En y réfléchissant, ce que tu dit pourrais être pratique pour la compréhension du code.
    Mais j'ai l'impression que cela reviens à dire qu'une entité est forcement alloué dynamiquement. Ce qui me gêne un peu.

    Perso, j'ai l'impression que les références sont mieux comprise que les pointeurs. Ou plutôt mieux utilisé. Je trouve que dès qu'il y as un pointeur y as 10000 cas possible pour qu'il soit invalide. Alors qu'un référence y en as 100.

    [edit]
    Remarque en Qt
    les QObject (classes entités) sont utilisés sous forme de pointeur
    les classes valeurs (QString, QVector,...) sont utilisés en copy et const référence. Ou en pointeur quand c'est une sortie.

  5. #65
    screetch
    Invité(e)
    Par défaut
    Disons que dans la plupart des cas cette définition me convient.
    J'essaye de me tenir a ce qui suit:
    * une valeur est definit avec le mot clé struct, et ne contient pas d'entité (mais eventellement un pointeur sur une entité), donc n'est qu'une aggrégation de valeurs
    * une valeur devrait redéfinir les opérateurs ==, = ainsi qu'un constructeur de copie et (souvent) un operateur <. En tous cas, ceux-ci ont un sens même s'ils n'existent pas.
    * les valeurs sont passés par copie ou par référence pour éviter la copie

    * une entité est définie avec le mot-clé class
    * une entité pourrait contenir une autre entité, bien que dans la plupart des cas il s'agit de pointeurs sur des entités
    * une entité peut contenir des valeurs
    * les opérateurs == ou < n'ont pas vraiment de sens
    * les entités sont manipulées en general via des pointeurs


    En prenant ces définitions j'ai du mal a voir dans quel cas (non tordus) une entité peut ne pas être allouée dynamiquement. Disons que c'est plus rare d'utiliser une entité "localement", c'est plutot le travail d'une valeur

    Dans le cas plus haut, ce qui me choque dans l'exemple de dédé c'est ce code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void DoSomething(const MyObject& o) { o.SpeakUp(); ... }
    ou MyObject est une entité.
    Ce code a peu de sens, et j'ai cherché a savoir ce qui me chiffone. Le passage d'une référence constante sur cet objet n'a pas vraiment de sens...
    Or, MyObject est une entité (l'opérateur d'affectation n'a pas vraiment de sens, et il est impossible de définir logiquement un opérateur ==, et pas de copie possible). En effet, MyObject est juste une aggrégation de comportements.
    Ce qui semble naturel pour moi c'est d'ecrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void DoSomething(MyObject* o) { o->SpeakUp(); ... }
    la je vois parfaitement ce que ca veut dire et l'utilisation d'un pointeur (bien qu'il soit nu, et ca je ne cautionne pas forcément) résout le problème de l'auteur.

    Et ca ne me choque pas que toute les entités d'un programme soient allouées dynamiquement, ce qui me choque c'est l'allocation dynamique de valeurs

  6. #66
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Pour le 1-, il y a un problème je suis d'accord, mais il est bien plus profond que const comme Joel l'a signalé.


    Pour le 2-, je partage l'avis de gbdivers. C'est déjà bien d'avoir une garantie entre moi et moi-même (mais aussi les autres dév). Si en plus le compilo vérifie les contrats pour nous, c'est magique! À moi ensuite de ne pas chercher à contourner les invariants et autres contraintes d'utilisation que je pense avoir identifiés.
    Et si je vois en cours de route je vois que j'ai eu la main trop lourde, je passe du cas restreint (à hypothèses simplificatrices) au cas général.

    Accessoirement, tu viens de nous dire que les types ne servent à rien car il y aura toujours un couillon pour les réinterpréter des int en double.


    Pour le 3-, J'ai déjà re-constifier des codes qui ne l'étaient pas. Souvent, il s'agissait de codes qui ne m'appartenaient pas, vu que je mets les const dès le début.
    Du temps perdu ? Oui et non, ce fut aussi l'occasion de rentrer dans un code développé par un autre.

    EDIT: zut, j'ai validé le message trop tôt.
    Concernant la maintenabilité, dans "char* Func(int*, float*);" je lis que les deux buffers en entrée vont être altérés (ben oui, ce ne sont pas des références qui sont prises, donc c'est tableau C en in/out). Or je ne veux pas que la fonction que j'appelle les modifient. Que fais-je ? Ben je leur passe une copie. Et je perds du temps au passage à aller fouiller code & doc pour m'assurer que je ne perds pas la responsabilité de mes tableaux.

    Alors que "func(std::auto_ptr<int>, float& r, vector<double> cont& )" me dit que la fonction va assumer la responsabilité d'un pointeur sur un (seul) int, modifier un flottant (éventuellement lire sa valeur), et utiliser sans altérer un vecteur qui est reçu en paramètre.
    Côté maintenance, c'est clair comme de l'eau de roche, nul besoin d'aller ouvrir la doc ou le code pour savoir ce que je dois dupliquer, ce que je peux libérer, etc.
    Il arrive qu'en paramètre je puisse prendre un "T const*", mais malgré les ambiguïtés sémantiques possibles, je considère par défaut qu'il s'agit d'un tableaux d'éléments que je n'ai pas le droit de modifier, probablement des histoires trainantes d'interfaçage avec du C.


    Pour les références, j'ai suffisamment argumenté et illustré qu'elles n'apportent rien de plus que les pointeurs si ce n'est une certaine légèreté syntaxique. Je comprends l'argument que les références apportent une sécurité accrue, mais pouvez-vous illustrer vos propos?
    Il y a-t-il vraiment besoin d'écrire
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void f(T * p) {
        assert(p && "erreur de prog: je ne sais pas travailler avec un pointeur nul, mon dev est fainéant et refuse de perdre du temps sur les cas généraux qui ne riment à rien");
    }
     
    void g(T & v) {
        ...
    }
    pour comprendre pourquoi on prend systématiquement des références quand on a le choix ?


    b- J'ai expérience de deux situations de ce genre :
    - j'ai trop joué avec des templates et sans équipement pour en simplifier les messages d'erreur (static_assert, et autre logger à templates)
    - j'ai regardé un code d'un autre disposant du genre d'erreur que je ne commet plus (inversion entre , et ; etc)

    Et mes problèmes n'ont jamais été induits par des références.


    ------------
    Une référence et/ou un const prouvent plus qu'un TU vu qu'il faut le faire exprès pour les contourner. Ils sont vérifiés à la compilation, et ils m'évitent de faire un test qui valide que ma fonction me modifie pas le paramètre que je lui passe (cas du const), ou une batterie d'autres tests qui vérifient que ma fonction sera toujours appelée avec un pointeur non nul.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  7. #67
    Membre régulier

    Inscrit en
    Octobre 2010
    Messages
    50
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 50
    Points : 70
    Points
    70
    Par défaut
    Il y a-t-il vraiment besoin d'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void f(T * p) {
        assert(p && "erreur de prog: je ne sais pas travailler avec un pointeur nul, mon dev est fainéant et refuse de perdre du temps sur les cas généraux qui ne riment à rien");
    }
     
    void g(T & v) {
        ...
    }
    Prends ta fonction g, remplace la référence par un pointeur, recompile, et il n'y a pas magiquement plus de chances que v soit nul. On peut très bien s'assurer qu'un pointeur est non nul par design, sans besoin d'assertions ou autres. Il suffit de brièvement consulter n'importe quel code Java, C#, Python, Ruby, VB, etc., pour se rendre compte que dans ces langages où tout est une référence potentiellement nulle, on ne passe pas davantage son temps à faire des assertions ou à vérifier les valeurs de retour. (La gestion de mémoire automatique ne règle que le problème des références invalides, pas des références nulles.) Et qui plus est, on n'a pas deux syntaxes pour représenter la même chose, et on ne se pose jamais la question de laquelle faudrait-il choisir.

    De toute manière, le vrai problème ce sont les pointeurs et références invalides ("dangling"); la cause d'un pointeur nul est relativement simple à identifier, celle d'un pointeur ou d'une référence invalide, moins. Et à ce niveau le fait d'utiliser une référence n'offre aucune garantie particulière.

    Je ne nie pas le fait qu'il est parfois pratique d'utiliser une référence, comme dans ton exemple. Idem pour const, j'y reviendrai. Mais de façon générale, C++ est un langage inondé de fonctionnalités qui ne sont applicables que dans une minorité de cas, et quoiqu'elles puissent être utiles dans ces cas, le coût en complexité n'en vaut pas la peine d'après moi et mon expérience avec des langages plus simples. Je préfère un C++ quelque peu réduit et c'est comme ça que moi et mon équipe sommes les plus productifs. As-tu déjà essayé de faire un projet de taille moyenne sans le moindre const? Quand tu n'as même plus à te poser la question, c'est tout cette énergie que tu peux investir sur "résoudre le problème" plutôt que "se conformer au langage".

    Concernant const, je vais essayer d'être parfaitement clair. C++, comme tous les langages impératifs, est un langage où tout est mutable par défaut. Le principe d'un langage impératif est en effet de modifier l'état du programme de façon séquentielle. Or les langages impératifs offrent souvent une façon de garantir qu'un membre de donnée ne peut être accidentellement réassigné ("final" en Java, "readonly" en C#, etc.) En C++, const va beaucoup plus loin. Étant donné que const se propage à tout ce qu'il touche, on se retrouve avec un langage où tout doit être const par défaut, explicitement, et ce qui ne l'est pas doit même parfois être déclaré mutable. Comme tout est mutable par défaut en C++, il en revient au programmeur de renverser la vapeur en saupoudrant des const partout où il est possible d'en mettre. Et ainsi, const devient omniprésent. Chaque méthode non-const a son équivalent const, et on n'en finit plus de dupliquer les signatures. La question d'immutabilité se pose au plus fin niveau de granularité (chaque méthode, chaque paramètre, chaque niveau d'indirection d'un pointeur même), à chaque instant, alors qu'il est rare que l'immutabilité soit si importante. Quel temps perdu!

    En d'autres termes, si const pouvait être utilisé au besoin, je ne dirais pas non. Mais étant donné que c'est tout ou rien, je préfère rien. C'est clairement une fonctionnalité intrusive et qui interagit mal avec les templates comme j'ai illustré, donc mal pensée. C'est la faute de la spec des templates, oui, reste que ça brise const.

    Tu dis que tu as déjà eu à rectifier du code qui n'était pas const. Mais que fais-tu si tu ne peux pas le modifier? Si TypeA n'offre pas de méthode const, et que je ne peux modifier le code source de TypeA, eh bien zut je ne peux pas m'en servir dans les méthodes const de mon type. Que fais-je? Je créé des équivalents non-const. Et ainsi je me retrouve avec des signatures dupliquées (si ce n'est des implémentations dupliquées, dans le cas de templates). Maintenance : -1.

    Et oui, const sur un paramètre m'informe, sans avoir à lire la documentation, que tel paramètre ne sera pas modifié. Il m'informe aussi que si la fonction doit utiliser une certaine méthode de mon type, cette méthode devra être offerte en version const, ce que je ne peux savoir qu'en regardant son code source ou en tentant de compiler. Une simple description, qu'un bon IDE devrait faire apparaître sans même un clic, aurait eu le même effet sans imposer de contraintes sur mon code. Maintenance : -1.

    De plus, tu supposes qu'un paramètre pris par référence non-const sera modifié. Or, c'est ambigu en fait. Peut-être est-ce un simple oubli de la part de celui qui a écrit la fonction. Il vaudrait mieux lire la description de la fonction que d'essayer de deviner l'intention de son auteur. Maintenance : -1.

    Accessoirement, tu viens de nous dire que les types ne servent à rien car il y aura toujours un couillon pour les réinterpréter des int en double.
    Les types sont effectivement une chimère en C++ puisque ce avec quoi on interagit réellement, c'est de la mémoire brute. Or, reste que les types sont toujours utiles et toujours applicables. Ils ne garantissent rien, mais ils permettent au moins de diviser logiquement le programme, ce dont on aurait de la difficulté à se passer. Donc, chimère oui, mais chimère utile. const, quant à lui, ne garantit rien et ne fait que se répandre comme la peste.

  8. #68
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Il est vrai que le c++ à un problème dès qu'on touche aux template :

    La plupart des mots clés (const notamment) obligent de créer une autre version de la même fonction. Pour cela, il suffit de lire le header functional du standard (si on regarde celui de c++0x, on obtient en plus les && pour dire rvalue).
    Horrible tous ces templates alors que le code est le même !
    Le const est très contreproductif. Cependant, il y a obligation de le mettre (ou mettre des const_cast partout).

    Cependant, const a de nombreux avantages : il prévient la mauvaise utilisation : Combien de fois aurions nous vus "J'ai un problème avec std::string car il prend une mauvaise valeur après avoir appelé c_str() et avoir assigné la valeur".

    Toutefois, je pense que cette discussion ne devrais pas avoir lieu dans "Pointeur intelligent vs pointeurs bruts" (Une scission de la discussion ?)

    [EDIT]

    J'aurais tendance à être d'accord avec Dr Dédé quand il dit que les références ne permettent que des raccourcis syntaxiques : toute référence est remplaçable par un pointeur non null.
    La référence à le même défaut que le pointeur : elle peut être invalide.
    Si une fonction prend un pointeur, il suffit de dire en précondition : "le pointeur ne peut être null" et, à partir de ce point, soit on considère qu'il faut quand même faire un assert (pour ceux n'ayant pas lu) ou alors considérer qu'il n'est pas null.

    Mais la aussi, c'est une autre discussion : il ne s'agit pas de pointeurs intelligents et de pointeurs bruts...

    Pour en revenir au sujet, les pointeurs intelligents sont utiles car ils permettent d'éviter la fuite mémoire, même en cas d'exception (ce qui j'aurais tendance à dire que ce n'est pas grave puisque une exception est sensée être extrêmement rare...).

  9. #69
    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
    @NoIdea: A part qu'un pointeur peut-etre NULL alors qu'une référence non. Et si en effet une référence peut-etre invalide au même titre qu'un pointeur, ces cas sont souvent des erreur de programmation (comprendre qui n'existe pas si le programme est bien fait), alors qu'un pointeur NULL n'est en aucun cas un problème de programmation et à un vraie sens, et doit donc être traité. (sauf si le contrfat dit l'inverse, mais dans ce cas pourquoi prendre un pointeur ? Ca sera juste plus verbeux à écrire et difficile à lire.)

    @yan: Je ne comprend pas ton étonnement suite à l'édite de NoIdea, l'existence des deux versions pour chaque constante est primordiale, donc ce n'est pas inutile, et c'est bien une duplication de code (qu'on peut de temps en temps éviter, en jouant avec des cast par exemple, cf Eff++ item sur l'opérateur d'affectation je crois).

    @Dr Dédé:
    Tout les exemple que tu cites pour les const et les types sont vraie, mais ils supposent quand même un code de départ en désaccord avec ce qu'on dit. (même si ils fonctionnent )

    Tu dis que tout est mutables par defaut, et je veus bien te croire, mais si j'ai un objet (d'un type quelconque), et que je lui envoyes le message "afficher" il est clair que je ne m'attends pas à ce que l'objet soit modifié, c'est en partie ceci que garantie const : que l'utilisateur ne modifie pas d'objets à son insue (sa suppose que le code soit totalement const-correct).

    Pour tes exemple 1 et 3 (code de départ non const-correct et l'oublie), mélanger deux facon de coder conduit rarement à de bon résultat, et pour l'oublie : quand on fait une erreur c'est rare que ca marche bien ...

    Le C++ est quand même typé, on peut en effet réinterpréter les données, mais c'est aux risques et périls de celui qui le fait, donc à moins de "se tirer une balle dans le pied" (copyright koala) je ne crois pas que ce soit un réel problème. (Ou alors le problème est que le C++ permet ce genre de chose, mais c'est une tout autre discussion AMA).

  10. #70
    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
    J'ai déplacé les messages sur le mot clef const sur
    http://www.developpez.net/forums/d99...ts-clef-const/

    yan

Discussions similaires

  1. Réponses: 55
    Dernier message: 18/03/2014, 12h11
  2. Réponses: 13
    Dernier message: 27/04/2012, 16h03
  3. Les pointeurs intelligents
    Par MatRem dans le forum C++
    Réponses: 8
    Dernier message: 20/06/2006, 19h27
  4. pointeur intelligent??
    Par yashiro dans le forum C++
    Réponses: 3
    Dernier message: 04/04/2006, 08h08
  5. Pointeur intelligent boost : return NULL ->comment faire?
    Par choinul dans le forum Bibliothèques
    Réponses: 7
    Dernier message: 21/12/2005, 16h24

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