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 :

portée d'une instance retournée par une fonction


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    113
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 113
    Points : 41
    Points
    41
    Par défaut portée d'une instance retournée par une fonction
    Bonjour à tous.

    Il y'a un truc que je pige pas trop en C++.. Ne fait pas attention à la syntaxe, c'est la theorie qui m'interresse


    Imaginons une classe "voiture".

    Si dans une fonction "duplicate" je cherche à retourner un nouvel objet "voiture" je ne sais pas comment je doit m'y prendre et ce que cela implique. Par ex :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    voiture duplicate(){
         voiture v;
         return v;
    }
    ou

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    voiture* duplicate(){
         voiture v,*ptr;
         ptr=&v;
         return ptr;
    }

    Ce que je ne pige pas d'une part, c'est la portée. ici "v" est declaré et initialisé dans ma fonction duplicate. Donc normalement, une fois terminé, la mémoire devrait etre liberé. Dans ce cas, ces 2 principes sont-ils faux vue que je peut pas reutiliser le pointeur retourné ?

    En fait ce que je cherche à faire c'est declarer et initialiser un nouvel objet "v" en appellant la fonction duplicate();

    dans le genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    voiture v=duplicate();
    Mais cette ecriture est pas bonne. Si je passe par un pointeur est-ce que je suis obligé de faire un delete pour eviter une fuite de mémoire ?

    Je sais que je suis pas clair, j'ai bien besoin d'une chtite explication

    Merci !

  2. #2
    Membre éclairé Avatar de reggae
    Profil pro
    Inscrit en
    Août 2005
    Messages
    773
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Août 2005
    Messages : 773
    Points : 795
    Points
    795
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     
    duplicate(objet)
    {
    return objet;
    }
     
    ...
     
     
    voiture v=duplicate(objet_que_tu_veux_dupliquer);
    Je ne crois pas que c'est ça que tu cherches à faire...

  3. #3
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     voiture duplicate(){ 
         voiture v; 
         return v; 
    }
    Valable, ce qui est retourné n'est pas l'objet v mais une copie de l'objet v avant sa destruction en sortie de la fonction;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    voiture* duplicate(){ 
         voiture v,*ptr; 
         ptr=&v; 
         return ptr; 
    }
    Faux, tu retourne l'adresse d'un objet qui est détruit en sortie de la fonction donc qui n'existe plus. Ou alors, il faut l'allouer dynamiquement (new). Même chose si le retour est fait par reférence sur v.
    Normalement, pour ce problème, tu devrais écrire un constructeur par copie (si le constructeur par copie par défaut ne peut suffire) et surcharger l'opérateur = ce qui est plus dans la logique C++

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    113
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 113
    Points : 41
    Points
    41
    Par défaut
    Bonjour et merci beaucoup de la reponse rapide

    ok donc je vais rester sur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    voiture duplicate(){ 
         voiture v; 
         return v; 
    }
    Mais est-ce que la copie n'est pas gourmande en ressource cpu ?

    Du coup comment est-ce que je peux l'initialiser depuis un autre scope ? un truc du genre ? par ex :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    voiture v=duplicate();
    Mais dans ce cas je ne peux pas le creer dynamiquement ! non ?

  5. #5
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Mais est-ce que la copie n'est pas gourmande en ressource cpu ?
    Tout dépend de la taille de l'objet puisqu'un objet temporaire va être créé par copie, retourné par la fonction, copié dans sa destination puis détruit. Ce n'est pas effectivement économique
    Du coup comment est-ce que je peux l'initialiser depuis un autre scope ? un truc du genre ? par ex :
    Je ne comprends pas ce que tu veux dire
    Tu peux allouer dynamiquement dans ta fonction duplicate et renvoyer un pointeur mais il faut alors stocker le pointeur renvoyé par la fonction de façon à pouvoir faire le delete. C'est plus délicat à gérer.
    Réfléchis à la possibilité d'utiliser un constructeur par copie.

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    113
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 113
    Points : 41
    Points
    41
    Par défaut
    Arf.. je patauge completement la.

    Bon j'ai fait simple dans le cas de la voiture, mais en fait j'utilise un opperateur + qui est censé me retourner un nouvel objet.

    j'ai un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    voiture voiture::operator + (voiture *v){
         voiture nv;
         nv.x=x+v->x; // x est un int
         return v;
    }
    Ensuite j'ai :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    voiture vA,vB;
    voiture vC=vA+vB;
    printf("%d\n",vC.x);
    Je voulais savoir si pour vous cette ecriture est juste. Chez moi avec mon code complet (qui fait plus q'une simple addition) je me retrouve avec une Erreur de segmentation .

    Alors ptet que c'est le reste du code qui deconne.. Cette erreur semble survenir l'ors de l'appel du destructeur de la classe voiture. Dans le destructeur je fait juste un delete d'un tableau créé dynamiquement.

    Bref je rame.

  7. #7
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Ca ressemble fort à une classe copiable mal implémentée.

    Pour rappel, toute classe copiable doit avoir :
    • Un constructeur par défaut
    • Un constructeur par copie
    • Un destructeur
    • Un opérateur d'affectation

    Ensuite il faut que ces 4 là soient correctement implémentés, ce qui est rarement le cas.

    Donc montre les nous, on pourra t'en dire plus.

    A noter que si ta classe ne manipule pas de ressource, alors les versions générées par le compilo seront suffisantes, tu n'auras pas besoin d'écrire les 4 fonctions citées plus haut. Et si tu dois manipuler une ressource (par exemple un pointeur), alors tu peux l'envelopper dans quelque chose de copiable et sûr, voir par exemple les pointeurs intelligents.

  8. #8
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    voiture voiture::operator + (voiture *v){ 
         voiture nv; 
         nv.x=x+v->x; // x est un int 
         return v; 
    }
    Un opérateur + doit être une fonction externe à la classe (this ne joue pas de rôle particulier) éventuellement déclarée friend du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    voiture operator+( const voiture &a, const voiture &b)
    {
         voiture nv; 
         nv.x=a.x+b.x; // x est un int 
         return v; 
    }
    Dans ton écriture, avec
    ceci correspond à voiture or vB n'est pas un pointeur sur voiture. Tu n'as pas eu de warning ?

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    113
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 113
    Points : 41
    Points
    41
    Par défaut
    Bonjour loulou24 :-)

    Alors je n'ai pas de constructeur par copie. Est-ce obligatoire ?

    Oubliez ce que je vous ai mis plus haut, c'etait pour simplifier. Voila exactement ce que je fait : Il s'agit d'une classe String. (oui je sais y'en a deja des toutes faites, mais c'est un entrainement pour moi de le faire moi même ).

    Le constructeur actuel de ma classe initialise des valeurs :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
            size=100;
            length=0;
            value=new char[size+1];
            value[0]=0;
    Le tableau "value" est dynamique car il est possible que sa taille augmente au cours du temps. Mais la on en est pas la donc c'est pas traité.

    Le destructeur lui :

    Dans ce cas, l'operateur + doit generer un nouveau String dont le tableau de char "value" est une concatenation des tableaux des 2 operandes.

    J'ai des fonctions membres : setValue(char *) et addValue(char *) qui fonctionne apparament tres bien.

    Mon operateur + fait alors exactement ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    String String::operator + (char *s){
               String str;
               str.setValue(value); // on y met la valeur actuelle
               str.addValue(s); // on y ajoute l'operande de droite
               return str;
    }
    Au final pour faire mon test je fait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
            String A;
            A="salut";
            String C=A+" toi";
            printf("%s\n",C.value);
    et j'obtien :
    salut toi
    compile.sh: line 2: 29980 Erreur de segmentation ...
    Notez que cela fonctione tres bien quand je fait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
            String A;
            A="salut";
            String C;
            C.setValue(A);
            C.addValue(" toi");
            printf("%s\n",C.value);
    J'ai bien en sortie :

    salut toi
    C'est pour cela que je pige pas tres bien pourquoi cela ne marche pas. quand j'appelle setValue et addValue moi même cela marche tres bien. Mais quand je cherche à passer par l'operateur ça marche pas .

    Voila a tous les coup j'ai pas pensé à un truc bête.

    Merci en tous cas à celui qui lira ce post et m'eclairera sur le prob.

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    113
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 113
    Points : 41
    Points
    41
    Par défaut
    Arf je pense avoir compris ce qui se passe. dites moi si c'est bien ça :

    La copie temporaire de l'objet copie tous y compris le pointeur "value". Donc cette copie de pointeur pointe toujours vers le même tableau en mémoire "value". du coup l'appel du destructeur de l'objet temporaire detruit aussi celui de l'operande. Au final un appel successif sur un objet deja detruit me met une erreur de segmentation.

    Est-ce cela ?

  11. #11
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    C'est ca . Tu es dans le cas signalé par Loulou24 où tu as l'obligation d'écrire un constructeur par copie où la chaîne elle-même est copiée.

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    113
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 113
    Points : 41
    Points
    41
    Par défaut
    Et bien merci beaucoup à tous, cela devient limpide pour moi maintenant.

    @+

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

Discussions similaires

  1. Réponses: 8
    Dernier message: 05/04/2011, 08h06
  2. Réponses: 1
    Dernier message: 13/04/2010, 10h00
  3. Concaténer une variable retourner par une fonction
    Par neogamaes dans le forum MATLAB
    Réponses: 9
    Dernier message: 17/02/2010, 16h49
  4. Réponses: 7
    Dernier message: 04/06/2008, 18h50
  5. Valeur retourné par une instance
    Par vdumont dans le forum Général Python
    Réponses: 1
    Dernier message: 04/05/2007, 21h21

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