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 :

programme plante si tableau supprimé


Sujet :

C++

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Points : 16
    Points
    16
    Par défaut programme plante si tableau supprimé
    Bonjour,

    Je developpe beaucoup en Java et je suis actuellement des cours de C++

    Je travaille sur des exercices et là il y en a un sur lequel je bute.

    Le voici : je dispose d'une classe F qui a pour attributs un tableau et sa taille.
    Son constructeur est vide mais un setter petmet d'initialiser (et changer) le tableau et sa taille.
    La classe dispose aussi d'une methode affichant les valeurs du tableau sur la console

    Le but de l'exo et d'utiliser un tableau (et non un vector) et de résoudre le problème du cas où on supprimerait le tableau avant d'appeler la méthode print()
    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
     
    #include <iostream>
    #include "f.h"
     
    using namespace std;
     
    F::F()
    {
    }
    F::~F()
    {
        delete[] tab;
    }
     
    void F::setTab( int *_tab, int _tabLength)
    {
        tab=_tab;
        tabLength=_tabLength;
    }
     
    void F::print()
    {
        int i=0;
        for(i=0;i<tabLength;i++)
            cout<<"TAB["<<i<<"]="<<tab[i]<<endl;
    }
    je n'ai pas mis le header qui contient simplement les signature des fonctions ainsi que le tableau et sa taille en attribut.

    Le problème est que si dans le main on fait ceci dans le main:

    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
     
    F* f = new F();
     
        int * tab= new int[10];
        int length=0;
        tab[length++]=20;
        tab[length++]=15;
        tab[length++]=10;
        tab[length++]=20;
     
     
     
        f->setTab(tab,length);
        delete[] tab;
        f->print();
    ça plante ce qui est normal.

    Je dois modifier le code en utilisant nottament un ou des "const" pour ne plus qu'il soit possible d'avoir ce problème.

    Avez vous une idée ?

    Merci beaucoup

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Prends un crayon, et exécute ton main à la main, en représentant chaque variable.
    Suppose que malloc retourne l'adresse 0x2A. (C'est arbitraire, bien sûr)

    Que fait print, et pourquoi ce n'est pas le problème?
    Elle affiche le contenu du tableau d'une variable membre (privée).

    Où est le problème?
    variable membre privée = variable que la classe garantie de toujours être correcte.
    Ce n'est apparemment pas le cas.

    Regarde qui modifie ou initialise cette variable, c'est là que tu trouveras les problèmes.

    Au passage, que se passe-t-il si on appele deux fois setTab() avant print()? ou pas du tout?
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #3
    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
    Bah je vois pas 300 solutions, et absolument rien lié au const.
    print devrait être const, mais c'est juste par const-correctness, et n'a rien à voir avec ton "problème".
    La classe devrait juste devenir propriétaire du tableau, ou s'en faire une copie.
    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.

  4. #4
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Et initialiser son pointeur dans son constructeur par défaut
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  5. #5
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    Bienvenue dans les joies du C++ !

    Un premier conseil: quand tu codes en C++, oublie toutes tes certitudes Java. Tu dois gérer toi même ta mémoire! Pour éviter de le faire manuellement, c'est-à-dire éviter de mettre des new et des delete dans ton code, il faut que tu encapsules la gestion de la mémoire dans des classes comme ta classe F: le code appelant F ne doit pas voir la gestion de la mémoire.

    Dans ce cas simple, tu devrais avoir:
    - un constructeur sans argument:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    F() : ptr(nullptr), size(0) {} // la syntaxe (recommandée) est Cteur() : member(init), member2(init2), ... , membern(initn) { corps du constructeur }
    - un autre pour créer un tableau:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    F(int sz) : ptr(new int[sz]), size(sz) {}
    -et bien sûr un destructeur qui libère la mémoire:
    Si tu veux étoffer ta classe avec des "setters" il faut réfléchir un peu plus au sens de l'opération. En C++ tu as deux types de sémantique:
    - copy: F f = ptr_vers_tableau <=> copie le tableau sur lequel pointe ptr_vers_tableau dans le tableau sur lequel pointe f.ptr; ce sont maintenant deux tableaux distincts
    - move: F f = ptr_vers_tableau <=> f.ptr = ptr_vers_tableau; ptr_vers_tableau = nullptr. Un seul tableau, donc un seul possesseur du tableau. Sinon arrive au problème que tu as eu

    Lequel veux-tu?

  6. #6
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    C'est un bon conseil, il manque juste le mot clé: RAII (ou parfois RFID). C'est le sigle qui désigne cette technique, et qu'on trouve appliquée dans std::vector (un tableau de ce type), std::unique_ptr.
    Cette technique peut s'appliquer pour d'autre type de recssources comme des connexions réseaux, une image, un fichier (std::fstream, par exemple), et plein d'autres choses, encore.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  7. #7
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Points : 16
    Points
    16
    Par défaut
    merci à tous pour vos réponses rapides

    Je trouvais aussi bizarre que la consigne dise qu'en maniant un const on puisse résoudre le problème.

    Effectivement je trouve que le fait de recopier le tableau dans le constructeur (et donc en devenir l'unique propriétaire) est une excellente idée !

    Le move aussi est une bonne idée. Mais je pense que je vais plutôt utiliser un recopiage pour ne pas avoir de problème au cas où le pointeur vers le tableau utilisé dans le setter est const.

    Petite question de synthaxe :
    @stendhal666 tu dis que la bonne sythaxe est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    F() : ptr(nullptr), size(0) {}
    Je trouve la synthaxe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    F() : {ptr=nullptr; size=0;}
    plus simple (puisque plus proche de java)

    Y a t il une difference entre les deux façons d'ecrire le constructeur ?

    Merci beaucoup

  8. #8
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160

  9. #9
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    La FAQ est un peu mystérieuse pour un débutant sur le sujet, avec ses sémantiques de valeur et d'entité (même si j'ai plussoyé l'intervention de Ehonn).

    Il y a un certain nombre choses impossibles à faire avec la syntaxe F() { membre1 = X; ... }
    Par exemple si membre est une référence:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class F {
      int& _i;
    public:
      F(int& i) { _i = i; } // ne compilera pas: "la référence F::_i& n'est pas initialisée dans la fonction F::F(int&)"
    };
    En fait, avant le '{' du constructeur tu peux décider de l'initialisation des membres de la classe. Après le '{', ils ont été initialisés à leur valeur par défaut (je simplifie: la question de l'initialisation automatique est compliquée mais ce sera pour une autre fois) et tu leur assignes de nouvelles valeurs. Donc tu perds en performance et en possibilités (les références, pour un exemple simple, comme elles doivent toujours être initialisées).

    Par rapport à Java, C++ te donne un contrôle très fin sur tout ce que tu fais. C'est très bien si tu sais quoi en faire, très frustrant sinon. Mais je te donne à nouveau le même conseil: oublie Java quand tu codes en C++! Malgré certaines ressemblances générales dans la syntaxe et les conventions d'indentation, ce sont des langages parfaitement différents, avec chacun ses forces et ses faiblesses. Donc tu devrais presque au contraire choisir les syntaxes les plus éloignées de Java :-)

  10. #10
    Membre éprouvé Avatar de fenkys
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    376
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Octobre 2007
    Messages : 376
    Points : 1 054
    Points
    1 054
    Par défaut
    Bonjour,

    Le programme tel que tu l'as ecrit dans le post original oublie quatre éléments fondamentaux quand on travaille avec des pointeurs.
    1) Il faut toujours vérifier un pointeur avant de l'utiliser.
    2) Désallouer un pointeur ne change pas sa valeur. Elle libère juste la mémoire pointée.
    3) Tu dois avoir autant d'allocation que de désallocation de pointeur.
    4) On pourrait rajouter que désallouer un pointeur va invalider tous les pointeurs qui pointent sur la même zone mémoire.

    Je te laisse voir en quoi ton programme n'est pas conforme à ces quatre principes.


    PS: le RAII dont parle Leternel est un outils puissant qui permet de vérifier au moins deux de ces quatre points. Il ne se limite pas aux pointeurs d'ailleurs.

  11. #11
    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
    Citation Envoyé par fenkys Voir le message
    4) On pourrait rajouter que désallouer un pointeur va invalider tous les pointeurs qui pointent sur la même zone mémoire.
    Oui parce qu'on désalloue uniquement la mémoire pointée.
    Et btw pointeur !== d'allocation dynamique de mémoire. Il est nécessaire pour ça, mais n'a rien à voir. Un pointeur vers un objet de la stack ça existe.
    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.

  12. #12
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Janvier 2003
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations forums :
    Inscription : Janvier 2003
    Messages : 4
    Points : 10
    Points
    10
    Par défaut
    Ton probleme est que durant ton set (ligne 17 de ton f.cpp) tu copies le pointeur, pas les donnees.
    Donc a la ligne 14 de ton main, les données sont detruites, la ligne suivante, quand print essaye d'y acceder, sa te retourne n'importe quoi.

    Comme fenkys le dit si bien pense RAII, ton constructeur et setter ne doivent faire qu'un et surtout copier les données.

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

Discussions similaires

  1. [PHP 4] [Tableaux] Tableau : supprimer une clé par son N° d'ordre
    Par renaud26 dans le forum Langage
    Réponses: 2
    Dernier message: 14/07/2009, 10h02
  2. Problème avec strcpy : mon programme plante
    Par Titi41 dans le forum Débuter
    Réponses: 4
    Dernier message: 06/11/2008, 12h02
  3. envoyer alerte email quand un programme plante
    Par trucentete dans le forum Administration système
    Réponses: 2
    Dernier message: 04/09/2008, 19h31
  4. [Windows Forms] Programme plante, mais le jour seulement !
    Par Invité(e) dans le forum Windows Forms
    Réponses: 6
    Dernier message: 28/08/2008, 11h42
  5. Programme de variables tableau
    Par Wilvart dans le forum C++
    Réponses: 3
    Dernier message: 24/04/2006, 21h30

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