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 :

Variable statique locale à une fonction membre


Sujet :

Langage C++

  1. #21
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    La constance porte sur l'utilisation de la variable pas sur sa valeur effective :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    static volatile const TYPE &io_mem_map;
    void fonction_impure()
    {
    io_mem_map; // peut avoir un effet de bord indépendant des paramètres et ce même si l'instruction n'a l'air d'être qu'une lecture sans rien d'autre
    }

    @flob : 2 intérêts des fonctions pures : elles ne peuvent être évalués qu'une seule fois puis leur résultat 'caché' (transparance référentielle). L'autre avantage est la possibilité de réordonner différents appels indépendants (ça permet donc des optimisations)

  2. #22
    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
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    La constance porte sur l'utilisation de la variable pas sur sa valeur effective :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    static volatile const TYPE &io_mem_map;
    void fonction_impure()
    {
    io_mem_map; // peut avoir un effet de bord indépendant des paramètres et ce même si l'instruction n'a l'air d'être qu'une lecture sans rien d'autre
    }
    Un cas de "naïveté technique" de ma part: je ne parlais pas de référence constante à un objet pouvant être modifié par ailleurs (comme les références à des registres matériels ou autre réf constante à des valeurs pouvant varier par le biais d'évènements matériels ou d'autres références non constantes...). Par contre, le premier exemple évoqué (la valeur de PI) est bien une constante au sens mathématique et non syntaxique du terme...et là ça n'empêche pas une fonction d'être pure, comme le disait koala01: le résultat est toujours le même pour les mêmes paramètres.

    @Flob90: je ne suis pas entièrement d'accord avec toi: pour moi, fonction pure <=> le résultat est toujours le même pour les mêmes paramètres. Or si l'exception est lancée pour signaler que les valeurs de paramètres utilisées sortent du domaine de définition (un usage à mon sens normal), alors chaque fois qu'on appellera la fonction avec ces paramètres on obteindra l'exception en retour. Pour moi ça n'empêche donc pas la fonction d'être pure. (je ne parle pas d'autres cas où l'exception survient pour d'autres raisons, qui généralement impliquent des ressources extérieures indisponibles et autres états incorrects qui empêchent de toutes façons la fonction d'être pure...)

  3. #23
    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
    @therwald: Oui je suis totalement d'accord avec ta définition de la pureté, sauf que comme je le disais, je pense que les exceptions ne doivent être utilisées qu'en cas de rupture du contrat de la fonction (*), de là on en déduit qu'elle n'est pas réentrante, ce qui implique impure.

    (*) Dit autrement je ne considère pas le cas que tu cites comme une utilisation légitime des exceptions, j'utiliserais plutôt une assertion si vraiment je tiens à pister les erreurs de programmation.

    @3DArchi: J'avais pas posé la question ni dit le contraire, mais je suis d'accord et c'est une précision qui peut être utile

  4. #24
    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
    Citation Envoyé par Flob90 Voir le message
    rupture du contrat de la fonction
    Je ne suis pas certain de comprendre ce que tu entends par là, pourrais-tu préciser pour ma gouverne?
    EDIT: ma question n'est peut-être pas claire, donc je précise: pour moi, rupture du contrat de la fonction <=> bug
    A la base une fonction bien foutue respecte son contrat (et le contrat inclut parfois la description de cas (exceptionnels) où il n'est pas possible de répondre à la demande exprimée par l'appel ==> exception.)

  5. #25
    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
    Disons que j'ai une fonction qui créé un objet d'un certain type à partir d'un index conpris entre 1 et 10 et donne la responsabilité de la durée de vie à l'appelant.

    Le contrat pourra être :
    Entrée : un entier entre [1 et 10) (c'est la partie du contrat que doit respecter l'utilisateur)
    Sortie : Un pointeur sur l'objet créé.

    Une implémentation (T un type avec un constructeur prenant comme paramètre un type entier) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    T* function(char c)
    { return new T(c); }
    La programmation par contrat (*) me dit que si je respect le contrat d'entrée alors la fonction doit respecter le contrat de sortie, or si new ne peut allouer la mémoire nécessaire la fonction ne peut respecter son contrat (elle peut pas retourner un pointeur sur l'objet) : rupture du contrat. Par contre si je ne respecte pas le contrat d'entrée (je donne 0 comme entrée par exemple), la fonction n'a rien a respecter et peut avoir un comportement quelconque.

    AMA, le premier cas est un cas d'utilisation d'exception, alors que le second non (**). C'est d'ailleurs la politique utilisée par la bibliothèque standard si tu prètes attention au cas où sont lancées les exceptions (sauf quelques cas à part).

    Note au passage que ca apporte certains avantages : pas besoin de tester la non-nullité du pointeur retourné puisque le contrat m'assure que c'est un pointeur sur un objet. C'est d'ailleurs ce que tu fais quand tu utilises new (version classique) tu utilises ce qu'il te donne sans vérifier au préalable qu'il est non nul.

    (*) C'est juste une explication grossière, il y a peut-être des détails que je ne connais pas.

    (**) Une raison pourrait être que si tu fais une erreur sur les paramètres passés à l'appel tu ne peux pas réelement rétablir un fonctionnement correct : tu sais pourquoi la fonction ne peut se faire mais pas pourquoi les paramètres sont mauvais, comment les corriger ?

    Imagines une telle fonction, mets la dans un bloc try, mets des paramètres d'appel incorrect, que mets-tu dans le bloc catch correspondant pour récupérer un comportement correct ? A part stopper le programme tu ne peux rien faire : l'erreur se répétera tant que tu n'auras pas corrigé l'erreur dans le code pour qu'un tel appel ne puisse arriver : c'est une erreur de programmation (ie c'est le développeur qui s'est planté).

  6. #26
    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
    OK
    Merci pour ces explications, je me coucherai moins bête ce soir

    Pour ce qui est des paramètres d'appel, concernant les paramètres incorrects pour cause de programmation incorrecte, je suis d'accord avec toi.
    Par contre je pense que l'équivalence valeurs hors domaine = erreur de programmation a des exceptions.
    Par exemple: les paramètres d'appel viennent d'une source de données quelconque. Les valeurs en question proviennent d'un processus différent de celui qui traite. Nous considérons que dans le cas normal les données seront correctes.
    Exemple de traitement d'exception: envoi d'un message d'exploitation signalant la présence de données incorrectes, à corriger, puis passage à la suite des données.
    Sur ce cas, il me semble normal d'utiliser un lancement d'exception.

  7. #27
    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
    Citation Envoyé par therwald Voir le message
    Par contre je pense que l'équivalence valeurs hors domaine = erreur de programmation a des exceptions.
    Humour involontaire

  8. #28
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    AMA, le premier cas est un cas d'utilisation d'exception, alors que le second non (**).
    std::invalid_argument ne sert pas dans ce genre de cas ?

    Citation Envoyé par Flob90 Voir le message
    C'est d'ailleurs ce que tu fais quand tu utilises new (version classique) tu utilises ce qu'il te donne sans vérifier au préalable qu'il est non nul.
    L'opérateur new ne lance pas un std::bad_alloc lorsqu'il ne peut pas allouer la mémoire ?

  9. #29
    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
    @Steph_ng8: Oui, mais elle est loin d'être très utilisée (*) ("sauf quelques cas à part"). Pour new (version classique), oui il lance, mon message ne dit pas le contraire.

    @therwald: Si ta source de donnée peut te donner des paramètre invalides, alors je pense que c'est plutôt dans ton programme que tu dois vérifier la validité avant d'appeler la fonction (entre la récupération des données et l'appel), et pas directement dans celle-ci.

    (*) Ma suggestion de regarder la bibliothèque standard s'appliquait plus spécifiquement à l'ensemble itérateurs/conteneurs/algorithmes.

  10. #30
    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
    Une autre raison d'utiliser des traitements par exceptions dans le cas d'erreurs de validité des paramètres est que parfois on ne peut assurer facilement la détection...l'erreur peut être du genre plus subtile qu'un null ou un 11 pour une plage 0..10, du coup l'assert ne suffit pas car alors on veut du diagnostic et report même en prod

  11. #31
    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
    Citation Envoyé par Flob90 Voir le message
    @therwald: Si ta source de donnée peut te donner des paramètre invalides, alors je pense que c'est plutôt dans ton programme que tu dois vérifier la validité avant d'appeler la fonction (entre la récupération des données et l'appel), et pas directement dans celle-ci.
    Je pense que ça se discute car en fonction de la complexité de l'appli cela peut mener à un clutter de la couche appelante...pour moi, quelque part, c'est à la fonction de savoir quel est son domaine de définition.

  12. #32
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Le contrat engage un code vis à vis d'un autre. Donc tout ce qui vient de l'extérieur - donnée dans une base, saisie utilisateur, message réseau, registre µ, etc... - doit être vérifié avant d'être propagé dans le code.


    Programmation par contrat, application en C++ par Julien Blanc

  13. #33
    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
    @3DArchi merci, en lisant quelques lignes du document j'ai compris le concept et la raison derrière.
    @Flob90 du coup je comprends ton point de vue.
    Ca ne s'applique pas à mon environnement professionnel, où faire confiance à l'appelant est trop risqué (je suis donc plutôt dans un contexte de programmation défensive).

  14. #34
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par therwald Voir le message
    Ca ne s'applique pas à mon environnement professionnel, où faire confiance à l'appelant est trop risqué (je suis donc plutôt dans un contexte de programmation défensive).
    La conséquence est un code 'enflé' et du masquage de bug. Mais, je comprends cette barrière 'culturelle' souvent dans le monde embarqué qui fait s'accrocher à une programmation défensive.

  15. #35
    screetch
    Invité(e)
    Par défaut
    je trouve l'exemple de flob mal choisi; appeler new rend deja la fonction impure, et c'est le comprtement de new qui est deja impur dans ta méthode.
    par exemple, une fonction pure devrait en permanence retourner le même pointeur si tu l'appelles avec les mêmes paramètres, ce que new ne fait pas.

    pour un exemple plus simple, prenons la méthode "acos"; acos a une valeur d'entrée qui doit être comprise entre -1 et 1, au dela le résultat est (un nombre complexe mais en général on s'en fout) indéfini.

    la méthode:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    float acos(float x)
    {
      if(x < -1 || x > 1)
        throw MathError(x);
      else
        return (developpement de taylor de x);
    }
    cette fonction peut être considérée comme pure; si tu appelles acos(-2) elle fera toujours la même chose, a l'infini. si tu appelles acos(0.1) aussi. pas comme new(int) ou etc etc.



    cependant même si d'un certain point de vue cette méthode est pure, la pureté dans certains langages est utilisée pour mettre un résultat en cache et ne pas rappeler la fonction; par exemple, les vieux jeux vidéo avaient une table de cos(x) pour x entre 1 et 180 pour ne pas recalculer cos(x). Or, c'est possible seulement parce que cos(x) est pure. Si une exception est levée par une méthode, même si c'est systématique, il va etre difficile d'utiliser une fonction pure comme une fonction pure; en effet, si acos(x) renvoie une exception, elle ne renvoie pas le résultat; il faudrait donc un systéme de cache qui est capable de traiter les cas exceptionnels aussi.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    float sqrcos = cos(x)*cos(x);
    ce code pourra etre optimisé puisque cos est pure;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    float sqracos = acos(x)*acos(x);
    celui la possiblement aussi puisque l'exception n'est pas traitée;
    au dela de ces exemples simples cela commencera a ressembler a un casse tête pour le compilateur. Autant dire que même si dans la logique c'est pur, dans les faits ca ne sera sans doute pas une fonction pure.

  16. #36
    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
    @screetch: Mon exemple n'avait rien à voir avec la pureté mais avec la programmation par contrat (*). Pour ton exemple, j'essaie justement d'argumenter dans ce message que c'est une utilisation assez critiquable des exceptions (donc j'allais pas en faire un exempl ). Pour résumer le raisonnement que j'ai fait (qu'il soit juste ou non ) : exception => rupture de contrat => non réentrante => impure. Ton exemple n'entre pas dans la première implication, issue de la programmation par contrat, d'où la conclusion à laquelle tu arrives (fonction pure lancante).

  17. #37
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    @Steph_ng8: (...) Pour new (version classique), oui il lance, mon message ne dit pas le contraire.
    Désolé, j'avais lu trop vite.
    En relisant le message, j'ai compris où tu voulais en venir.

Discussions similaires

  1. Variable static dans une fonction membre
    Par uriotcea dans le forum C++
    Réponses: 8
    Dernier message: 09/07/2009, 14h48
  2. Variable locale à une fonction.
    Par MoiRemi dans le forum PL/SQL
    Réponses: 7
    Dernier message: 04/02/2009, 17h05
  3. [NASM] Variables locales à une fonction
    Par Rémiz dans le forum x86 16-bits
    Réponses: 2
    Dernier message: 13/11/2008, 10h33
  4. variable statique d'une fonction, locale à un thread?
    Par coyotte507 dans le forum Threads & Processus
    Réponses: 5
    Dernier message: 29/06/2007, 12h54
  5. Réponses: 14
    Dernier message: 05/09/2006, 01h17

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