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 :

Erreur du compilateur ou erreur de language ou normal ?


Sujet :

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 Erreur du compilateur ou erreur de language ou normal ?
    Bonjour,

    pourquoi ce bout de code fonctionne (testé avec gcc-4.7) ?

    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
     
    #include <iostream>
     
    using namespace std;
     
    struct S
    {
        void p(){ cout << "test" << endl; }
    };
     
    int main()
    {
        S* a = nullptr;
        a->p();
        return 0;
    }
    Je ne m’attendais pas du tout à ce que ce code puisse fonctionner puisqu'en apparence, je créé juste un pointeur vers une classe, sans jamais instancier l'objet en question ! Vous avez une idée de qui fait une erreur ?
    Nullius in verba

  2. #2
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par Kaamui Voir le message
    Je ne m’attendais pas du tout à ce que ce code puisse fonctionner puisqu'en apparence, je créé juste un pointeur vers une classe, sans jamais instancier l'objet en question ! Vous avez une idée de qui fait une erreur ?
    Tu n’utilises pas le this dans ta fonction, et elle n’est pas virtuelle.

    Comme ta fonction n’est pas virtuelle, le code que va générer le compilateur va ressembler à quelque chose comme :

    - appelle le bout de code situé à l’adresse X (l’adresse de p() ) en lui passant comme premier paramètre un pointeur contenant l’adresse de a (celui auquel on va pouvoir accéder en tant que this dans S::p()).

    Comme ensuite, ce paramètre / this n’est jamais utilisé, ça fonctionne car… tu ne déréférences jamais ce pointeur null.

    Ce serait différent si tu utilisais this, ou si la méthode était virtuelle (car alors, le simple fait d’appeler la méthode nécessiterait de connaître le type réel de l’objet, et donc introduirait un déréférencement.

    Je pense cela dit que c’est un comportement indéterminé (même si ça va donner la même chose sur tous les compilos en release — en debug ça se discute). En revanche, si ta fonction n’est pas virtuelle et n’utilise pas this, elle devrait être statique (et là, tu verrais pourquoi ça fonctionne).

  3. #3
    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
    Je ne comprends pas pourquoi l'adresse de p() est elle bien réelle..

    Au moment ou j'utilise l'opérateur '->', je ne déréférence pas a ?

    Si je comprends ce que tu dis, la "vie" de la fonction p ne dépend pas de celle de a ? Autrement dit, lorsque je créé une classe comme S, la méthode S::p() est instanciée un bonne fois pour toute, et c'est toujours celle-ci qui est utilisée par tous mes objets c'est ça (en même temps c'est logique et ça fait de sacrées économies ..) ?

    Néanmoins, je ne devrais pas pouvoir y accéder (idéologiquement) alors qu'aucun objet instancié n'y a été lié (passé en paramètre).. si ?

    Est-ce que le langage (sa norme) prévoit ceci ? Peut-on attendre d'un compilateur qu'il gère ce genre de cas ou cela ne peut être visible qu'à l'éxécution (ça métonnerait) ?
    Nullius in verba

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Doctorant
    Inscrit en
    Novembre 2012
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2012
    Messages : 15
    Points : 25
    Points
    25
    Par défaut
    Bonjour,

    La réponse que j'allais faire tombe à plat puisque l'explication vient juste d'être donnée mais ce code pourra la compléter.

    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
    24
    25
    26
    27
     
    #include <iostream>
     
    using namespace std;
     
    struct S
    {
    	int val;
    	void p(){ cout << "test S " << val << endl; }
    };
     
    class T
    {
    	public :
    	static void p(){ cout << "test T" << endl;}
    };
     
    int main()
    {
    	S a;
    	a.val = 10;
    	a.p();
     
    	T* t = nullptr;
    	t->p();
    	return 0;
    }
    Et confirme que le comportement est indéterminé car si on écrit

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    	S* a = nullptr;
    	a->p();
    	T* t = nullptr;
    	t->p();
    La compilation va se faire et le programme évidemment plantera, S n'étant pas instancié.

  5. #5
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Citation Envoyé par Kaamui Voir le message
    Je ne comprends pas pourquoi l'adresse de p() est elle bien réelle..

    Au moment ou j'utilise l'opérateur '->', je ne déréférence pas a ?

    Si je comprends ce que tu dis, la "vie" de la fonction p ne dépend pas de celle de a ? Autrement dit, lorsque je créé une classe comme S, la méthode S::p() est instanciée un bonne fois pour toute, et c'est toujours celle-ci qui est utilisée par tous mes objets c'est ça (en même temps c'est logique et ça fait de sacrées économies ..) ?

    Pour voir ce qui passe, il suffit de comprendre que le code généré va ressembler a ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    #include <iostream>
     
    using namespace std;
     
        void MANGLING_S_p(S* this){ cout << "test" << endl; }
     
     
    int main()
    {
        S* a = nullptr;
        MANGLING_S_p(a);
        return 0;
    }
    Donc techniquement parlant, ya aucune raison que ca plante, vu que tu ne vas jamais deferencer a. Comme l'a dit white_tentacle, un acces a un membre ou a une fonction virtuelle changerait la donne.

    Apres, ca reste un undefined behaviour. Ca devrait planter mais ca plante pas !

    C'est moche mais c'est comme ca.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  6. #6
    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
    Citation Envoyé par Davidbrcz Voir le message
    Apres, ca reste un undefined behaviour. Ca devrait planter mais ca plante pas !
    Attention, undefined behaviour n'est pas synonyme de plantage.

    Cela signifie juste que la norme n'est pas arrivée à définir un comportement "qui serait cohérent" et qu'elle laisse donc le soin à l'implémentation de décider ce qu'elle devra faire.

    Cela sous tend le fait que deux compilateurs différents (ou deux versions différentes d'un même compilateur) peuvent parfaitement réagir différemment et que l'un pourra accepter le comportement et l'autre pourra le refuser

    En gros, en fonction du compilateur (ou de sa version), on "lance les dés", en espérant avoir un triple six
    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

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

Discussions similaires

  1. Erreur d'héritage ou erreur du compilateur?
    Par Klaim dans le forum C++
    Réponses: 2
    Dernier message: 31/01/2010, 22h59
  2. erreur de compilateur
    Par Christinita dans le forum MATLAB
    Réponses: 2
    Dernier message: 21/11/2008, 14h57
  3. Réponses: 1
    Dernier message: 02/11/2007, 13h28
  4. Réponses: 4
    Dernier message: 31/03/2005, 17h55
  5. F1004 Erreur du compilateur interne
    Par psau dans le forum C++Builder
    Réponses: 2
    Dernier message: 15/09/2004, 16h12

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