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 :

Redimentionner une instance dynamique d'une classe


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Inscrit en
    Septembre 2009
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Septembre 2009
    Messages : 4
    Par défaut Redimentionner une instance dynamique d'une classe
    Bonjour,

    Mon problème se pose car je ne peux pas utiliser les "vector" puisqu'il s'agit d'un exercice scolaire.

    La faq dit à ce sujet
    "Pour agrandir une zone (généralement un tableau) allouée via l'opérateur new il faudra faire la manipulation à la main :
    - Allouer un nouvel espace mémoire de la taille souhaitée
    - Y copier son contenu
    - Libérer l'ancien espace mémoire ".

    En tentant cette approche "bête et méchante", je me bute à un autre problème car je souhaite que ma nouvelle instance ait le même nom : la portée des variables.
    Voilà ce que je tente de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    maClass * pointeurSurInstance
    while(cin>>item){
       if(monInstance.monTableau.estRempli()){
          maClass nouvelleInstance(de taille plus grande); //alloue un nouvelle espace plus grand
          recopier(pointeurSurInstance, nouvelleInstance);//copie le contenu
          pointeurSurInstance = &nouvelleInstance;
       } *1*
       
       //...
       //agit sur l'instance pointée par pointeurSurInstance en fonction de cin
       //...
    }
    Bon, j'imagine que vous voyez le problème, au niveau de *1* nouvelleInstance est libérée grâce au destructeur de classe donc pointeurSurInstance ne pointe sur rien.

    Je n'ai aucune idée de la manière de faire pour résoudre le problème.

    D'avance merci.

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut, et bienvenue sur le forum.

    La solution la plus simple étant toujours la moins compliquée... heu, je veux dire: la meilleure, passe toi, tout simplement, de l'allocation dynamique de la mémoire sur ce coup

    Comme tu l'a si bien remarqué, il faudrait veiller à libérer correctement la mémoire de ton tableau de taille inférieure après avoir correctement copié son contenu dans le tableau de taille supérieure, ce qui t'amènerait à écrire 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
    12
    13
    14
    15
    16
    17
    maClass * pointeurSurInstance;
    size_t size =0;
    while(cin>>item){
        /* mettons la taille à jour */
        ++size;
        /* créons un tableau temporaire capable de contenir le bon nombre
         * d'objets
         */
        maClass* temp = new maClass[size];
        /* copions le contenu du tableau d'origine dans le second */
        memcpy(temp,pointeurSurInstance,sizeof(maClass)*(size-1));
        /* libérons la mémoire du tableau d'origine */
        delete[] pointeurSurInstance;
        /* et assignons le nouveau tableau à notre pointeur "de travail" */
        pointeurSurInstance = temp;
        /* n'oublions pas d'initialiser le nouvel élément ;) */
    }
    Mais, il se fait que C++ fournit tout ce qu'il faut pour s'éviter d'avoir à gérer soi-même la mémoire pour les collections d'objets.

    Ainsi, on dispose de la classe vector, disponible dans l'espace de noms std par simple inclusion du fichier d'en-tête <vector>, qui propose l'ensemble des comportements que l'on peut s'attendre de la part d'une collection d'objets pour laquelle tous les objets sont contigüs en mémoire.

    Pour information, il existe d'ailleurs une foule de conteneurs adaptés aux différents besoins, allant de la pile au tableau associatif clé / valeur en passant par les tableaux d'éléments contigus en mémoire, la file, la liste et les arbres binaires.

    Tu peux te baser sur cette entrée de la FAQ afin de déterminer quel conteneur sera le plus adapté à tes besoins

    Si tu choisi la classe vector, par exemple, tu peux t'en sortir avec un code aussi simple que:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    std::vector<MaClass> tableau;
    while(cin >> item) // je considère ici que item est de type MaClass ;)
                       // et que maClass est copiable 
    {
        tableau.push_back(item);
    }
    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

  3. #3
    Futur Membre du Club
    Inscrit en
    Septembre 2009
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Septembre 2009
    Messages : 4
    Par défaut
    Re-bonjour et merci pour le message de bienvenue.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        /* créons un tableau temporaire capable de contenir le bon nombre
         * d'objets
         */
        maClass* temp = new maClass[size];
    Je n'ai pas été très clair : maClass contient une instance d'une classe qui contient un tableau. De plus, le redimentionnement de mon tableau dynamique doit être exponentiel (doublé à chaque fois que la place vient à manquer). Du coup, je ne peux pas procéder à un redimentionnement à chaque tour dans la boucle while. Donc toutes ces opérations se font dans un environnement "if" (if(taille inssufisante). Il me semble que la solution que tu proposes ne convient pas car à chaque fin de "if" la variable temp sera détruit par le destructeur de la class maClass. À moins que je ne comprenne pas quelque chose ?

    Enfin, comme je l'ai précisé dans mon premier poste, je suis dans la contrainte de gérer moi-même le redimentionnement (pas d'utilisation d'un conteneur de haut niveau).

    Dans tous les cas merci de ta réponse rapide !

    Je reste donc à la recherche d'une solution si celle-ci ne convient pas (comme je le crois pour le moment).

    En revanche je ne comprends pas pourquoi

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par reveilla Voir le message
    Re-bonjour et merci pour le message de bienvenue.
    Et oui, que veux tu, j'ai reçu une éducation, et non un élevage
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        /* créons un tableau temporaire capable de contenir le bon nombre
         * d'objets
         */
        maClass* temp = new maClass[size];
    Je n'ai pas été très clair : maClass contient une instance d'une classe qui contient un tableau. De plus, le redimentionnement de mon tableau dynamique doit être exponentiel (doublé à chaque fois que la place vient à manquer). Du coup, je ne peux pas procéder à un redimentionnement à chaque tour dans la boucle while. Donc toutes ces opérations se font dans un environnement "if" (if(taille inssufisante). Il me semble que la solution que tu proposes ne convient pas car à chaque fin de "if" la variable temp sera détruit par le destructeur de la class maClass. À moins que je ne comprenne pas quelque chose ?
    Ici, je croyais que ce que tu voulais était un tableau de maClass...

    Mais le principe reste exactement le même, si ce n'est que le pointeur est un membre de maClass

    Ce serait donc 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
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    class MaClass
    {
        public:
            MaClass():size_(1),nbr_(0),ptr_(new Type[size_]){}
            ~MaClass()
            {
                /*destruction "finale" */
                delete ptr_;
            }
            void addItem( Type const & t)
            {
                if(nbr_==size_)
                {
                    size_*=2;
                    Type * temp=new Type[size];
                    memcpy(temp,ptr_,nbr_*sizeof(type));
                    delete[] ptr_;
                    ptr=temp;
                }
                /* affectation des valeurs adhoc à l'élément */
                ptr[nbr_].truc=t.truc;
                /* incrémentation du compteur */
                ++nbr_;
            }
        private:
            /* le nombre maximale avant redimentionnement */
            size_t size_;
            /* le nombre d'éléments reellement maintenus */
            size_t nbr_;
            /* le pointeur représentant le tableau contigu */
            Type * ptr_;
    };
    L'idée est, en effet, de faire en sorte que la responsabilité qui consiste à décider (ou non) d'augmenter la taille du tableau qu'elle contient ne revienne qu'à la classe elle-même

    Cette classe sera utilisée sous une forme (en respectant ton code d'origine) proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void foo()
    {
        maClass * pointeurInstance = new maClass;
        while(cin>>item)
        {
            pointeurInstance->add(item);
        }
    }
    voire, de préférence (je l'ai dit, il ne faut utiliser l'allocation dynamique qu'en cas d'absolue nécessité )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void foo()
    {
        maClass instance;
        while(cin>>item)
        {
            instance.add(item);
        }
    }
    Enfin, comme je l'ai précisé dans mon premier poste, je suis dans la contrainte de gérer moi-même le redimentionnement (pas d'utilisation d'un conteneur de haut niveau).
    Quelle drôle d'idée...

    Cela revient à te couper une jambe parce que tu n'a pas l'intention de participer au 110 mètres haies aux prochains jeux olympiques, en oubliant que ta jambe peut te servir à marcher

    A moins que tu ne nous dise pas tout et qu'il s'agisse, en réalité, d'un exercice donné par le professeur...

    Auquel cas, je ne me generais absolument pas pour lui faire remarquer que c'est bien gentil de réinventer la roue, mais que cela n'apporte rien à la compréhension du langage (en plus de nous mettre dans une situation dans laquelle nous risquons énormément de commettre des erreurs )
    Dans tous les cas merci de ta réponse rapide !
    Mais de rien
    Je reste donc à la recherche d'une solution si celle-ci ne convient pas (comme je le crois pour le moment).
    Il faut laisser croire les béguines, elles sont spécialistes, et payées pour

    Plus sérieusement, je n'avais "simplement" pas compris que pointeurInstance devait lui-même agir comme un conteneur
    En revanche je ne comprends pas pourquoi
    Parce que, comme tu avais assez mal exprimé ton problème, j'ai choisi une solution qui ne correspondait effectivement pas tout à fait...

    Peut-être devrais tu lire ma signature et réfléchir un peu au bon conseil qu'elle tente de faire passer
    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

  5. #5
    Futur Membre du Club
    Inscrit en
    Septembre 2009
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Septembre 2009
    Messages : 4
    Par défaut
    L'idée est, en effet, de faire en sorte que la responsabilité qui consiste à décider (ou non) d'augmenter la taille du tableau qu'elle contient ne revienne qu'à la classe elle-même
    Voilà, c'est exactement ce qu'il me manquait. En effet, que la classe s'occupe elle-même des détails concernant l'ajout d'un objet semble naturel (une fois que l'idée nous a été soufflé ). Cela permet de cacher un peu plus le fonctionnement de la classe et ça rend le code moins lourd/plus facile à comprendre.

    Bref, je vais tenter d'écrire moi-même cette méthode qu'il me manque dans ma classe. Je n'ai pour le moment pas trop regarder (pour me laisser travailler un peu ) mais je garde ça sous le coude pour vérifier/m'aider en cas de blocage.

    Merci bien koala01.

    A moins que tu ne nous dise pas tout et qu'il s'agisse, en réalité, d'un exercice donné par le professeur...
    J'avais écris ceci lors de mon premier post :

    Mon problème se pose car je ne peux pas utiliser les "vector" puisqu'il s'agit d'un exercice scolaire.
    Donc je ne cache rien mais il s'agit bien d'un exercice pédagogique. Une consigne de notre enseignant afin de nous faire manipuler les tableaux dynamiques je suppose. Je suis en tout point d'accord avec ta remarque sur le fait que ça revient à ré-inventer la roue. Je pense que c'est dans un but pédagogique je crois, avoir une idée de comment fonctionne la classe vector et prendre conscience qu'il n'y a pas d'équivalent à "realloc" en C++.

    Voilà, espérons que je ne revienne pas poster sur ce post, ça sera bon signe

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par reveilla Voir le message
    Donc je ne cache rien mais il s'agit bien d'un exercice pédagogique. Une consigne de notre enseignant afin de nous faire manipuler les tableaux dynamiques je suppose. Je suis en tout point d'accord avec ta remarque sur le fait que ça revient à ré-inventer la roue. Je pense que c'est dans un but pédagogique je crois, avoir une idée de comment fonctionne la classe vector et prendre conscience qu'il n'y a pas d'équivalent à "realloc" en C++.

    Voilà, espérons que je ne revienne pas poster sur ce post, ça sera bon signe
    Ouppss... j'avais lu un peu trop en diagonale

    Ceci dit, tu pourrais tenter d'expliquer au prof que, les possibilités offertes par le langage lui-même aidant, il est vraiment conseillé de limiter l'utilisation de la gestion dynamique de la mémoire aux cas pour lesquels il n'existe pas d'autre choix, et que les cas en questions tournent le plus souvent autour du polymorphisme et / ou de l'envie (du besoin) de faire en sorte que la durée de vie des objets ne dépende pas de l'objet au travers duquel ils sont créés

    manipuler new / new[] et delete, delete[] uniquement pour le plaisir revient dans bien des cas à risquer de se tirer une balle dans le pied... (la preuve: je me rend compte que mon code comporter une erreur que je corrige de suite )
    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. Réponses: 8
    Dernier message: 26/03/2010, 08h16
  2. Réponses: 5
    Dernier message: 22/09/2008, 07h47
  3. Créer une instance dynamiquement
    Par stephane_78 dans le forum LabVIEW
    Réponses: 2
    Dernier message: 13/12/2007, 09h26
  4. copie d'une table Y d'une base A vers une table X d'une base
    Par moneyboss dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 30/08/2005, 21h24

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