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 :

copier le contenu d'un struct passé en ref dans un tableau de struc


Sujet :

Langage C++

  1. #1
    Membre averti
    Avatar de onet
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    365
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2002
    Messages : 365
    Points : 344
    Points
    344
    Par défaut copier le contenu d'un struct passé en ref dans un tableau de struc
    Hello,

    Voila, la situation initale:

    J'ai un struct que je passe en référence à une fonction. Cette fonction à pour but de recevoir ce struct, et d'en faire une copie dans un tableau de struct. Comment je le fais? Je n'y arrive pas!

    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
     
    struct msg {
        int    cmd_id;
        int    lenght;
        char * params;
        bool urgent;
     
    };
     
    msg list_msg[MSG_NBR_MAX];
     
    bool Queue::send_msg( msg * message ){
     
        int pos;
     
        if( this->end_list + 1 != this->start_list ){
            if(this->end_list != MSG_NBR_MAX - 1)
                pos = this->end_list + 1;
            else
                pos = 0;
     
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
     
            this->end_list++;
        }
     
        return true;
    }
    la ou y a les XXXXXXXXXXX, je dois copier le contenu de mon message (le contenu, pas sa référence) dans mon tableau de struct. J'ai essayé:
    this->list_msg[pos].cmd_id = message.cmd_id;

    Sans succès (avec *message.cmd_id, &message.cmd_id aussi) . Mes bases de C++ étant relativement lointaine, je nage un peu... Si qqun a une piste pour m'aiguiller?

    merci.
    Onet
    ---
    Retrouvez tout mes tutos et mes articles: http://www.olivierlange.com

  2. #2
    Membre averti
    Avatar de onet
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    365
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2002
    Messages : 365
    Points : 344
    Points
    344
    Par défaut
    C'est bon, résolu!

    Merci, et désolé du bruit!

    Onet
    ---
    Retrouvez tout mes tutos et mes articles: http://www.olivierlange.com

  3. #3
    Membre averti
    Avatar de onet
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    365
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2002
    Messages : 365
    Points : 344
    Points
    344
    Par défaut
    mmm...

    Petite précision... Y a pas moyen de faire plus "propre":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
            this->list_msg[pos].cmd_id = message->cmd_id;
            this->list_msg[pos].urgent = message->urgent;
            for(int i = 0; i < NBR_PARAMS_MSG; i++)
                this->list_msg[pos].params[i] = message->params[i];
    Sachant que ma struct est:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    struct msg {
        int    cmd_id;
        char params[NBR_PARAMS_MSG];
        bool urgent;
     
    };
    ???

    Onet
    ---
    Retrouvez tout mes tutos et mes articles: http://www.olivierlange.com

  4. #4
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 367
    Points
    50 367
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this->list_msg[pos] = *message;
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    memcpy(this->list_msg[pos], message, sizeof(this->list_msg[pos]));
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  5. #5
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Le this est n'est pas obligatoire.

    Soit dit en passant tu devrais regarder du côté de std::vector<>
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  6. #6
    Membre averti Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Points : 302
    Points
    302
    Par défaut
    Hello,
    Tu pourrais surcharger l'opérateur d'affectation de ta structure:
    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
     
     
    struct msg 
    {
        int    cmd_id;
        std::string params;
        bool urgent;
     
        msg & operator=(const msg & right)
        {
             cmd_id = right.cmd_id;
             params = right.params;
             urgent = right.urgent;
        }
     
    };
    A enjoliver ensuite en ajoutant un constructeur par copie.
    Dans tous les cas, je te déconseilles d'utiliser l'opérateur d'affectation sans le surcharger en gardant un char* pour params : tu feras une copie de pointeur (chaque params pointera vers le même emplacement mémoire), pas une copie du contenu (à moins que cela ne soit ce que tu souhaite).
    C'est vrai qu'un std::vector ou une std::list va te faciliter la vie dans ce cas.

  7. #7
    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
    Citation Envoyé par onet Voir le message
    Hello,

    Voila, la situation initale:

    J'ai un struct que je passe en référence à une fonction. Cette fonction à pour but de recevoir ce struct, et d'en faire une copie dans un tableau de struct. Comment je le fais? Je n'y arrive pas!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    struct msg {
        int    cmd_id;
        int    lenght;
        char * params;
        bool urgent;
     
    };
    <snip>
    Sans succès (avec *message.cmd_id, &message.cmd_id aussi) . Mes bases de C++ étant relativement lointaine, je nage un peu... Si qqun a une piste pour m'aiguiller?
    Salut,

    Tu devrais déjà prendre l'habitude de préférer en toute circonstance la classe string dispponible dans l'espace de noms std par simple inclusion du fichier d'en-tête <string> pour manipuler tes chaines de caractères...

    En effet, cette classe est bien plus sécurisante à l'emploi que les chaines de caractères "C style" (tableau de craractères terminé par un '\0'), surtout lorsqu'il s'agit de manipuler des chaines de caractères de longueur variable ou pour lesquelles il t'es impossible / difficile de déterminer une taille maximale cohérente.

    Bien souvent, dans ce genre de situation, tu te retrouve à manipuler, comme tu le fais ici, des char* et à utiliser la gestion dynamique de la mémoire (malloc / new / new[] et free / delete / delete[]) avec tous les risques que cela peut comporter de fuites mémoire, de double libération de la mémoire voire, de dépassement d'index (tout ce qui consiste à essayer de faire entrer N caractères dans un tableau qui ne peut en contenir que... N-1) en devant, de plus, garder une trace du nombre de caractères réellement utilisés et de la taille maximale admise pour la chaine

    De plus, si tu as *vraiment* besoin de récupérer un char* correspondant à la chaine std::string (pour le passer en paramètre d'une fonction, par exemple), il t'est toujours possible d'invoquer la fonction membre c_str()

    Le tout sans parler du fait que, si tu écris un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    /* N'essayez pas chez vous */
    char *first="hello";
    char *second=" world";
    char * final = first + second;
    tu utilise en fait l'arithmétique des pointeurs et tu ne copie absolument pas le contenu de first ni de second dans final
    Citation Envoyé par vikki Voir le message
    Hello,
    Tu pourrais surcharger l'opérateur d'affectation de ta structure:
    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
     
     
    struct msg 
    {
        int    cmd_id;
        std::string params;
        bool urgent;
     
        msg & operator=(const msg & right)
        {
             cmd_id = right.cmd_id;
             params = right.params;
             urgent = right.urgent;
        }
     
    };
    A enjoliver ensuite en ajoutant un constructeur par copie.
    Dans tous les cas, je te déconseilles d'utiliser l'opérateur d'affectation sans le surcharger en gardant un char* pour params : tu feras une copie de pointeur (chaque params pointera vers le même emplacement mémoire), pas une copie du contenu (à moins que cela ne soit ce que tu souhaite).
    Oui, et non...

    Oui si l'on se base sur l'exemple de onet qui manipule un pointeur de char, non si on se base sur le tien...

    Selon l'exemple de onet, nous en arriverions à quelque chose 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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    struct msg {
        int    cmd_id;
        int    lenght;
        char * params;
        bool urgent;
        /* Après tout, donnons nous l'occasion de construire un msg 
         * "d'une traite"
         */
        msg(int id,int l,char* p, bool u):cmd_id(id),lenght(l),
            params(new char[l]), urgent(u)
        {
            strncpy(params,p,l);
        }
        /* constructeur par copie */
        msg(msg const & m):cmd_id(m.cmd_id),lenght(m.lenght),
            params(new char[m.lenght]),urgent(m.urgent)
        {
            strncpy(params,m.params,lenght);
        }
        /* opérateur d'affectation */
        msg & operator = (msg & rhs)
        {
            /* utilisons notre constructeur par copie */
            msg temp(rhs);
            /* intervertissons les membres entre "this" et "temp" */
            std::swap(cmd_id,temp.cmd_id);
            std::swap(lenght,temp.lenght);
            std::swap(params,temp.params);
            std::swap(urgent,temp.urgent);
            /* temp sera automatiquement détruit (et son destructeur appelé)
             * ce qui fait que la mémoire allouée aux pointeur qui apartenait
             * avant à this sera libérée
             */
            return *this;
        }
        /* le destructeur */
        ~msg()
        {
            delete[] params;
            params = 0;
        }
     
    };
    En effet, la redéfinition du constructeur par copie, de l'opérateur d'affectation et du destructeur est indispensable si leur comportement n'est pas trivial, ce qui est le cas lorsque l'on gère dynamiquement la mémoire et les pointeurs.

    Le constructeur par copie devrait donc veiller à allouer dynamiquement la quantité de mémoire adéquate pour params (selon l'exemple), le destructeur devrait veiller à libérer correctement cette mémoire et l'opérateur d'affectation devrait, dans l'idéal, utiliser l'idiôme copy-and-swap

    Par contre, dans ton exemple à toi, les comportement du constructeur par copie, de l'opérateur d'affectation et du destructeur sont tout à fait triviaux, du seul fait que l'ensemble des membres disposent eux aussi de constructeurs par copie (ou de pseudo constructeurs par copie, pour les types primitifs), d'opérateur d'affectation et de destructeurs.

    Or, il faut savoir que le compilateur fournit d'office un constructeur par copie, un opérateur d'affectation et un destructeur si tu ne les déclares pas toi-même (la nouvelle norme permettra de les déclarer deleted afin d'interdire la copie ou l'affectation), et qu'il présentent exactement le comportement trivial adapté (copie membre à membre pour le constructeur par copie, idiome copy-and-swap pour l'opérateur d'affectation et destruction des membres dans l'ordre inverse de leur déclaration pour le destructeur).

    Si ces comportements conviennent à ta structure ou à ta classe, et que tu ne veux pas, par exemple, rendre le destructeur virtuel dans une hiérarchie de classe, tu as bien souvent carrément intérêt à laisser le compilateur les implémenter par lui-même

    (Pour rappel, la seule différence qu'il existe, en C++, entre une structure et une classe tient dans la visibilité par défaut de leurs membres et de l'héritage: ils seront private pour les classes et public pour les structures )
    C'est vrai qu'un std::vector ou une std::list va te faciliter la vie dans ce cas.
    Sur ce point, par contre, nous sommes tous catégoriques
    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

  8. #8
    Membre averti Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Points : 302
    Points
    302
    Par défaut
    Citation:
    Envoyé par onet Voir le message
    Hello,

    Voila, la situation initale:

    J'ai un struct que je passe en référence à une fonction. Cette fonction à pour but de recevoir ce struct, et d'en faire une copie dans un tableau de struct. Comment je le fais? Je n'y arrive pas!

    Code :


    struct msg {
    int cmd_id;
    int lenght;
    char * params;
    bool urgent;

    };
    <snip>


    Sans succès (avec *message.cmd_id, &message.cmd_id aussi) . Mes bases de C++ étant relativement lointaine, je nage un peu... Si qqun a une piste pour m'aiguiller?
    Salut,

    Tu devrais déjà prendre l'habitude de préférer en toute circonstance la classe string dispponible dans l'espace de noms std par simple inclusion du fichier d'en-tête <string> pour manipuler tes chaines de caractères...

    En effet, cette classe est bien plus sécurisante à l'emploi que les chaines de caractères "C style" (tableau de craractères terminé par un '\0'), surtout lorsqu'il s'agit de manipuler des chaines de caractères de longueur variable ou pour lesquelles il t'es impossible / difficile de déterminer une taille maximale cohérente.

    Bien souvent, dans ce genre de situation, tu te retrouve à manipuler, comme tu le fais ici, des char* et à utiliser la gestion dynamique de la mémoire (malloc / new / new[] et free / delete / delete[]) avec tous les risques que cela peut comporter de fuites mémoire, de double libération de la mémoire voire, de dépassement d'index (tout ce qui consiste à essayer de faire entrer N caractères dans un tableau qui ne peut en contenir que... N-1) en devant, de plus, garder une trace du nombre de caractères réellement utilisés et de la taille maximale admise pour la chaine

    De plus, si tu as *vraiment* besoin de récupérer un char* correspondant à la chaine std::string (pour le passer en paramètre d'une fonction, par exemple), il t'est toujours possible d'invoquer la fonction membre c_str()

    Le tout sans parler du fait que, si tu écris un code proche de
    Code :

    /* N'essayez pas chez vous */
    char *first="hello";
    char *second=" world";
    char * final = first + second;


    tu utilise en fait l'arithmétique des pointeurs et tu ne copie absolument pas le contenu de first ni de second dans final
    Citation:
    Envoyé par vikki Voir le message
    Hello,
    Tu pourrais surcharger l'opérateur d'affectation de ta structure:
    Code :



    struct msg
    {
    int cmd_id;
    std::string params;
    bool urgent;

    msg & operator=(const msg & right)
    {
    cmd_id = right.cmd_id;
    params = right.params;
    urgent = right.urgent;
    }

    };


    A enjoliver ensuite en ajoutant un constructeur par copie.
    Dans tous les cas, je te déconseilles d'utiliser l'opérateur d'affectation sans le surcharger en gardant un char* pour params : tu feras une copie de pointeur (chaque params pointera vers le même emplacement mémoire), pas une copie du contenu (à moins que cela ne soit ce que tu souhaite).
    Oui, et non...

    Oui si l'on se base sur l'exemple de onet qui manipule un pointeur de char, non si on se base sur le tien...

    Selon l'exemple de onet, nous en arriverions à quelque chose proche de
    Code :

    struct msg {
    int cmd_id;
    int lenght;
    char * params;
    bool urgent;
    /* Après tout, donnons nous l'occasion de construire un msg
    * "d'une traite"
    */
    msg(int id,int l,char* p, bool u):cmd_id(id),lenght(l),
    params(new char[l]), urgent(u)
    {
    strncpy(params,p,l);
    }
    /* constructeur par copie */
    msg(msg const & m):cmd_id(m.cmd_id),lenght(m.lenght),
    params(new char[m.lenght]),urgent(m.urgent)
    {
    strncpy(params,m.params,lenght);
    }
    /* opérateur d'affectation */
    msg & operator = (msg & rhs)
    {
    /* utilisons notre constructeur par copie */
    msg temp(rhs);
    /* intervertissons les membres entre "this" et "temp" */
    std::swap(cmd_id,temp.cmd_id);
    std::swap(lenght,temp.lenght);
    std::swap(params,temp.params);
    std::swap(urgent,temp.urgent);
    /* temp sera automatiquement détruit (et son destructeur appelé)
    * ce qui fait que la mémoire allouée aux pointeur qui apartenait
    * avant à this sera libérée
    */
    return *this;
    }
    /* le destructeur */
    ~msg()
    {
    delete[] params;
    params = 0;
    }

    };

    En effet, la redéfinition du constructeur par copie, de l'opérateur d'affectation et du destructeur est indispensable si leur comportement n'est pas trivial, ce qui est le cas lorsque l'on gère dynamiquement la mémoire et les pointeurs.

    Le constructeur par copie devrait donc veiller à allouer dynamiquement la quantité de mémoire adéquate pour params (selon l'exemple), le destructeur devrait veiller à libérer correctement cette mémoire et l'opérateur d'affectation devrait, dans l'idéal, utiliser l'idiôme copy-and-swap

    Par contre, dans ton exemple à toi, les comportement du constructeur par copie, de l'opérateur d'affectation et du destructeur sont tout à fait triviaux, du seul fait que l'ensemble des membres disposent eux aussi de constructeurs par copie (ou de pseudo constructeurs par copie, pour les types primitifs), d'opérateur d'affectation et de destructeurs.

    Or, il faut savoir que le compilateur fournit d'office un constructeur par copie, un opérateur d'affectation et un destructeur si tu ne les déclares pas toi-même (la nouvelle norme permettra de les déclarer deleted afin d'interdire la copie ou l'affectation), et qu'il présentent exactement le comportement trivial adapté (copie membre à membre pour le constructeur par copie, idiome copy-and-swap pour l'opérateur d'affectation et destruction des membres dans l'ordre inverse de leur déclaration pour le destructeur).

    Si ces comportements conviennent à ta structure ou à ta classe, et que tu ne veux pas, par exemple, rendre le destructeur virtuel dans une hiérarchie de classe, tu as bien souvent carrément intérêt à laisser le compilateur les implémenter par lui-même

    (Pour rappel, la seule différence qu'il existe, en C++, entre une structure et une classe tient dans la visibilité par défaut de leurs membres et de l'héritage: ils seront private pour les classes et public pour les structures )
    Citation:
    C'est vrai qu'un std::vector ou une std::list va te faciliter la vie dans ce cas.
    Sur ce point, par contre, nous sommes tous catégoriques
    J'avoue avoir choisi la réponse courte brutale et peu claire par flemme. Du coup, c'est le juste retour de flamme ^^

Discussions similaires

  1. Copier le contenu d'un .docx pour l'ajouter dans un autre .docx
    Par ahmedpa dans le forum Général Java
    Réponses: 17
    Dernier message: 17/07/2013, 13h27
  2. afficher le contenu d'une table de ma BDD dans un tableau
    Par nono2009 dans le forum Struts 2
    Réponses: 1
    Dernier message: 22/06/2009, 20h14
  3. Réponses: 1
    Dernier message: 05/12/2006, 10h40
  4. Réponses: 8
    Dernier message: 25/01/2006, 20h32
  5. Réponses: 2
    Dernier message: 20/11/2005, 18h54

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