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 :

références vs pointeurs Quand les utiliser ?


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Par défaut références vs pointeurs Quand les utiliser ?
    Bonjour à tous,

    Une question existentielle aujourd'hui : "quelle est la différence fondamentale entre les références et les pointeurs (nus ou 'intelligents') ?"
    Car autant j'utilise les références à foison, partout où je peux, autant je vois pas mal de gens qui utilisent encore les pointeurs (des gens qui semblent quand même savoir ce qu'ils font).
    Du coup je me demande, sous quelles conditions on peut estimer nécessaire d'utiliser des pointeurs plutôt que des références ?
    Peut-être ne s'agit-il que d'une question d'habitudes ou de goût ?

    Merci d'avance.

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Mes rules of thumb :
    1. n'utilise pas de pointeur
    2. si tu n'as pas le choix, utilise des pointeurs.
    3. avant d'appliquer la règle 2, relis la règle 1


    Des cas où tu n'as pas le choix : interagir avec des API C, interagir avec des API C++ qui demandent des pointeurs, pointer vers une valeur optionnelle.


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

    Informations professionnelles :
    Activité : aucun

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

    Les règles citées par Bktero sont parfaites, j'aurais simplement énoncé la première sous la forme de "utilises les référence partout où tu peux, ou tu en as besoin"

    L'utilisation de pointeur ne doit se faire que si tu n'as vraiment pas d'autre choix, car elle te forcera à sécuriser au maximum les différents accès que tu tenteras de faire à l'élément pointé.

    Il y aura quatre raisons pour lesquelles tu peux ne pas avoir le choix.

    1- parce que tu veux représenter une donnée qui peut ne pas exister.

    Si tu veux représenter un graphe ou un arbre, par exemple, "il se peut" que tu éprouves le besoin de fournir une référence vers "le noeud parent" pour chaque noeud. Evidemment, le noeud racine n'aura pas de parent, et il faut donc pouvoir représenter le fait que la donnée n'existe pas

    Nous pourrions bien envisager d'utiliser std::optional depuis C++17, mais ce n'est pas prévu pour.

    2- lorsque tu dois t'interfacer avec une API écrite en C, car C ne dispose que des pointeurs et la notion de référence est inconnue en C.

    3- Lorsque tu veux manipuler des classes faisant partie d'une hiérarchie de classes, le tout, en les considérant comme si chaque instances étaient du type de base. Un petit exemple pour comprendre:

    Soient les classes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class Base{
    public:
        Base() = default;
        Base(Base const &) = delete;
        Base & operator=(Base const &) = delete;
        ~Base() = default;
        /* ... */
    };
    class Derivee1 : public Base{
        /* ... */
    }:
    class Derivee2 : public Base{
        /*...*/
    };
    /* ... */
    class DeriveeN : public Base{
        /* ... */
    };
    Plus loin, tu vas avoir un code qui créera une instance (qui "passe pour être du type de base") dont le type réel dépendra "des circonstances", par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    /* une enumeration permettant de savoir quel type de donnée créer */
    enum DataType{
        first,
        second,
        /* ... */
        enieme
    };
    /* j'utilise les pointeurs intelligents, parce qu'il faudrait le faire de manière systématique */
     
    std::unique_ptr<Base> createData(DataType dt /*, ... */){
        switch(dt){
            case first:
                return std::make_unique<Derivee1>();
            case second:
                return std::make_unique<Derivee2>();
            /* ... */
            case enieme:
                return std::make_unique<Derivee3>();
            default:
                assert(false && "You should never come here!");
        }
        return std::unique_ptr<Base>{nullptr};
    }
    (NOTA: je n'ai pas cherché à faire quelque chose de parfaitement correct, mais bien à te donner l'idée générale )

    Ou peut-être voudras tu -- simplement -- pouvoir maintenir (avec la notion de propriété qui va bien) un ensemble d'instances de classes dérivée de Base dans une collection spécifique

    Tu n'auras alors pas d'autre choix que de passer par l'allocation dynamique de la mémoire (et par l'utilisation des pointeurs intelligents, tant qu'à faire). Cela prendrait une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    std::vector<std::unique_ptr<Base>> tab;
    for(/*...*/ ){
        /* ... */
        tab.emplace(std::move(createData(/* ... */)));
    }
    Par contre, maintenant que tu es sur que chaque pointeur se trouvant dans le tableau existe -- vu que la mémoire qui lui est allouée est automatiquement libérée lorsque le pointeur intelligent est supprimé du tableau -- tu n'as plus aucune raison (en dehors du fait de transférer la propriété du pointeur à une fonction, s'entend) de transférer l'élément pointé par pointeur, car tu as la certitude qu'il existe.

    Tu pourrais donc avoir une fonction proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void foo(Base /* const*/ & b){
        /* utilise le polymorphisme :D */
    }
    qui serait appelée pour chaque élément de ton tableau sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for(auto /* const */ & it: tab){ // it est une référence sur std::unique_ptr
        foo(*it.get()); // on fournit à foo "ce qui est pointé" par l'élément renvoyé par la fonction membre get()
    }
    4- La dernière raison est d'utiliser une bibliothèque externe qui est "prévue comme cela".

    La bibliothèque Qt, par exemple a été développée bien avant que les pointeurs intelligents ne soient mis au point. Elle a mis au point un système "parent / enfants" par lequel, dés que tu définis un élément (une boite de dialoguqe, par exemple) comme le "parent" d'un autre (un bouton, par exemple), la libération de la mémoire allouée au parent provoque automatiquement la libération de la mémoire allouée à tous ses enfants.

    Il est donc "normal" de traiter les pointeurs "assez légèrement" avec cette bibliothèque, pour la simple et bonne raison qu'ils sont traités "de manière transparente" par la bibliothèque elle-même
    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

  4. #4
    Membre éclairé Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Par défaut
    Bonjour, et merci pour ces retours.

    Je suis entièrement d'accord avec les règles que vos citez. Techniquement, cela fait un bon bout de temps que je n'ai pas eu à utiliser de pointeurs.
    Avec les cas cités par Koala1, globalement, je m’aperçois qu'il doit être tout de même relativement rare d'avoir à en passer par les pointeurs (dans le cas de la création d'un programme sans bibliothèque tierce).

    Merci pour vos retours. Dans tous les cas que j'ai rencontré jusqu'à présent donc, inutile pour moi d'utiliser les pointeurs.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par BioKore Voir le message
    globalement, je m’aperçois qu'il doit être tout de même relativement rare d'avoir à en passer par les pointeurs (dans le cas de la création d'un programme sans bibliothèque tierce).
    C'est, à vrai dire, beaucoup plus complexe que cela n'en a l'air, car cela dépendra énormément du domaine dans lequel tu travaille.

    Si tu travailles sur une application qui fait des math avancées, tu devrais pouvoir t'en passer "assez facilement" (si l'on décide d'ignorer que la plupart des collections utilisent des pointeurs en interne )

    Si tu travailles sur une bibliothèque graphique, ou -- tout simplement -- si tu as des "messieurs" et des "mesdames" qui doivent tous les deux être considérés comme "des gens" (sans distinction d'age ou de sexe), l'utilisation de pointeurs deviendra rapidement indispensable
    Merci pour vos retours. Dans tous les cas que j'ai rencontré jusqu'à présent donc, inutile pour moi d'utiliser les pointeurs.
    Tu as sans doute eu beaucoup de (mal) chance
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre éclairé Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Par défaut
    On dira simplement que les sujets étaient "simples".

    Cependant, je vois effectivement quelques cas d'application dans lesquels l'utilisation des pointeurs simplifie la tâche.
    Une simple fonction d'initialisation / paramétrage de membre dans une classe partagée et, effectivement, l'utilisation des références s'avère plus difficilement praticable.

    Mais au moins je visualise mieux les conditions d'application des pointeurs et le "pourquoi".

    Merci encore.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 14
    Dernier message: 25/10/2007, 15h00
  2. Exceptions, quand les utiliser
    Par Invité dans le forum Général Dotnet
    Réponses: 6
    Dernier message: 13/05/2007, 15h27
  3. [Smarty] Utilité ? Quand les utiliser ?
    Par Xunil dans le forum Bibliothèques et frameworks
    Réponses: 25
    Dernier message: 28/11/2006, 17h08
  4. fonctions et classes... quand les utiliser ?
    Par fastmanu dans le forum Langage
    Réponses: 6
    Dernier message: 03/04/2006, 00h39

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