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 :

Préconditions des range-based for et de std::for_each ?


Sujet :

Langage C++

  1. #1
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut Préconditions des range-based for et de std::for_each ?
    Bonjour à tous,

    Je suis à mon boulot en train de faire du C# par manque de boulot C++, et je viens de m'apercevoir que le foreach en C# a la précondition que l'objet soit non nul (un objet instancié vide suffit pour qu'aucune exception ne soit levée). Je trouve cela assez dommage d'obliger l'utilisateur à vérifier lui-même que l'objet n'est pas nul de la façon suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    if (monObjet != null)
    {
       foreach(monType m in monObjet)
       {
     
       }
    }
    alors qu'il parait évident, que cette condition pourrait être vérifiée (en en plus je crois que de toute façon elle l'est, puisqu'une exception est levée) directement dans le code du foreach, ce qui aurait pour conséquence de reproduire exactement le même comportement que le code ci-dessus, mais d'économiser mes pauvres doigts ^^. j'aurais donc plusieurs questions pour ce sujet :

    - Premièrement, je comprend la stratégie mise en place côté C#, le choix était conceptuel, et ils on préféré faire lever une exception. Mais je n'aurais pas fait comme ça personnellement, car je trouve que cela ne devrait pas nécessairement être bloquant. Et vous ?
    - Enfin un rapport avec le C++ : comment les ranged-based for et std::for_each ou même boost::for_each (si le comportement est différent) sont ils gérés ? De la même façon ?
    - Connaissez vous un endroit sur le net où je puisse trouver des infos claires à ce sujet, sans vous déranger la prochaine fois.. le dernier draft côté C++ ? Et pour C# ? Pareil ?


    Merci d'avance pour vos réponses, et vos avis ^^
    Nullius in verba

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    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 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Salut,

    au début du message ça m'a paru bizarre, mais après réflexion : est-ce que ça vient pas du fait que pointeur/référence/etc sont cachés à l'utilisateur en C# (un peu comme en Java) ?

    Du coup, il faudrait s'assurer que le pointeur est bien valide avant d'itérer à travers d'hypothétiques valeurs.
    Si par contre il y a exception quand la liste est vide, alors là oui c'est con-con comme fonctionnement.

    Ce serait l'équivalent que:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // std::vector<int>* myVec
    foreach(int i : *myVec) {}
    plante si myVec est NULL. Et ce test (myVec != NULL) ne doit pas être fait par la boucle elle-même amha.
    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.

  3. #3
    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
    Si je ne me trompe pas, la bibliotheque standard ne comporte aucun type T tel que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    T* conteneur;
    for (auto x: conteneur) {
    }
    compile. On peut s'arranger de le faire (en définissant des fonctions libres begin(T*) et end(T*)), c'est a celui qui les définit de dire ce qui se passe pour un pointeur nul.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  4. #4
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Si je ne me trompe pas, la bibliotheque standard ne comporte aucun type T tel que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    T* conteneur;
    for (auto x: conteneur) {
    }
    compile. On peut s'arranger de le faire (en définissant des fonctions libres begin(T*) et end(T*)), c'est a celui qui les définit de dire ce qui se passe pour un pointeur nul.
    Oui en effet, je n'avais pas réfléchi à cela. Donc en C++ logique.

    Par contre en C#, je ne trouve pas de quoi réfuter le "pourquoi pas ?" à l'humble avis de Bousk.
    Nullius in verba

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Le fait est que, en C#, tu travailles avec des références sur des objets "garbages collectés", ce qui fait que tout objet est susceptible d'exister, ou non, d'avoir été détruit parce que plus référencé, ou non...

    Il est donc "logique" dans ce sens, d'avoir mis une précondition d'existence sur l'objet, pour éviter d'aller chipoter à des endroits de la mémoire où ma chatte n'irait pas mettre son derrière .

    En C++, on peut utiliser les range-based loop sur
    1. un array alloué sur la pile (sans allocation dynamique)
    2. les collections de la stl
    3. un array alloué sur le tas (via new[])

    en (1), il y a d'office garantie de l'existence de l'array, car un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void foo()
    {
        {
            Type array[10];
            /*... */
        }
        for(auto truc : array)
        {
            /*... */
        }
    }
    sera purement et simplement refusé à la compilation, la boucle se trouvant hors de la portée d'existence de array .

    En (2), il y a aussi d'office garantie d'existence car, soit nous travaillerons avec la collection directement déclarée sur le tas (et on se retrouve dans le cas (1) ) , soit on travailleras sur une référence (éventuellement constante), et une référence donne aussi la garantie d'existence de l'objet référencé (éventuellement sous la forme d'une variable anonyme non nommée s'il s'agit d'une référence constante).

    Il n'y a donc, que dans le cas (3) que l'on peut, éventuellement, être confronté au problème, parce que le pointeur correspondant peut etre null ou que la mémoire peut avoir été libérée (par delete[]).

    A ce moment là, il t'appartient, comme toujours, de suivre une politique stricte de remise à null des pointeurs sur lesquels delete[] est invoqué ainsi que de test systématique de l'existence de l'objet pointé.

    Mais, si tu n'as pas la discipline de controler systématiquement tes pointeurs nus, tu auras bien des soucis autrement plus cuisants que ceux des (quelques) boucles que tu écriras

    Ca, c'était pour ce qui concerne l'existence même de l'objet sur lequel tu veux travailler.

    Reste l'éventuel problème de l'existence des objets itérés.

    Et, là encore, tu te trouves face à différentes possibilités:

    Soit tu vas travailler sur des (copies) d'objets, voire, sur des références, parce que tu as fait un array (dynamique ou non) d'objet ou parce que tu travailles (par exemple) sur un std::vector<Type>, et tu as, de toutes facons, la garantie de l'existence de l'objet en question.

    Soit tu travailles sur des pointeurs, parce que tu auras déclaré un array de pointeur (alloué dynamiquement ou non) ou parce que tu travailles avec une collection de la STL manipulant des pointeurs (ex std::vector<Type*> ).

    Et, les même causes ayant les mêmes effets, il n'y aura encore une fois que ta propre discipline concernant la gestion des pointeurs qui pourra te sauver.

    Mais, encore une fois, si tu n'as pas une discipline de gestion des pointeurs correcte, tu auras bien d'autres soucis que les quelques boucles que tu écriras
    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
    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 Kaamui Voir le message
    Par contre en C#, je ne trouve pas de quoi réfuter le "pourquoi pas ?" à l'humble avis de Bousk.
    Pour la même raison qu'en C un pointeur nul n'est pas un chaîne vide, une chaîne vide c'est un pointeur vers un char de valeur 0. Le fait que le déréférencement n'est pas marqué syntaxiquement n'empèche pas qu'il est là logiquement.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  7. #7
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Pour la même raison qu'en C un pointeur nul n'est pas un chaîne vide, une chaîne vide c'est un pointeur vers un char de valeur 0. Le fait que le déréférencement n'est pas marqué syntaxiquement n'empèche pas qu'il est là logiquement.
    Je sais tout cela (idem pour la réponse de Koala01). Ce que je dis, c'est que dans la logique de la grammaire qui a été choisie pour le langage C#, qui masque ce déréférencement à l'utilisateur, même s'il est évidemment là logiquement, on peut penser aller plus loin, et gérer "en intra" le test d'existence d'un l'objet passé en paramètre du foreach. Mais en y réfléchissant là ou je me rend compte que ma proposition est contraignante, c'est ici :

    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
     
    if (monObjet != null)
    {
       foreach (monType m in monObjet)
       {}
    }
    //ou
    foreach (monType m in monObjet)//avec le test inclu dans le code de foreach <= même résultat, moins contraignant pour l'utilisateur
     
    //mais...
    if (monObjet =! null)
    {
      foreach(monType m in monObjet)
      {}
    }
    else //pas de problème
    {
       doSomething();
    }
    //ou
    foreach(monType m in monObjet)//impossible de traiter le cas "else", à moins de reproduire le code du dessus, donc le test inclu ne sera à rien...
    Donc j'ai rien dit. Mais par contre sans cet argument les votres ne m'ont pas convaincu que ma proposition était une hérésie.
    Nullius in verba

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

Discussions similaires

  1. Traduction de "range based" for loop
    Par ram-0000 dans le forum Langage
    Réponses: 6
    Dernier message: 01/03/2013, 11h15
  2. VBA,Graphiques :Series qui pointent sur des Range Discontinu
    Par CCHEVALIER dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 27/09/2005, 14h05
  3. Réponses: 3
    Dernier message: 13/08/2004, 18h52

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