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 :

Passage par référence pour modifier une liste de string


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2016
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Afghanistan

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Août 2016
    Messages : 11
    Par défaut Passage par référence pour modifier une liste de string
    Bonjour,
    Je souhaite créer une liste de chaînes de caractères de type vector<char*> en C++ qui puisse accepter de nouvelles chaînes issues d'une variable de type string grâce à une fonction. J'ai fait un code sans fonction qui marche très bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void main()
    {
    vector<char*> listest(0); 
    string toto = "Hello";
    listest.push_back(const_cast<char*>(toto.c_str())); // J'ai dû rajouter const_cast<char*> pour passer en type char* car la méthode push_back n'acceptait pas toto.c_str() qui est de type const char*.
    cout << listest[0] << endl; 
    }
    En revanche, si je crée une fonction qui modifie directement listest (passage par référence), cela ne marche plus :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    void fct_test(vector<char*> *listref)
    {
    	 string toto = "Hello";
    	(*listref).push_back(const_cast<char*>(toto.c_str()));
    }
    void main()
    {
            vector<char*> listest(0);
    	fct_test(&listest);
    	cout << listest[0] << endl;
    }
    Quelqu'un saurait-il pourquoi ?
    Je me suis demandé si cela pouvait venir du passage par référence dans la fonction, mais si je fais le test suivant, cela fonctionne très bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    void fct_test(vector<char*> *listref)
    {
    	(*listref).push_back("Hello");
    }
    void main()
    {
            vector<char*> listest(0);
    	fct_test(&listest);
    	cout << listest[0] << endl;
    }
    Le problème vient donc de la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (*listref).push_back(const_cast<char*>(toto.c_str()))
    dans la fonction, mais cette ligne fonctionne très bien dans le main(), donc je ne comprends pas.

    Merci de votre aide,
    Andrew

  2. #2
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    Ces codes ont au minimum 3 problèmes:

    - Un usage abusif de pointeur là le bon sens voudrait une référence.
    - Vouloir manipuler des chaînes de caractères avec char*. Surtout quand l'origine est un std::string.
    - Caster le retour de c_str().

    Si tu veux comprendre ton erreur, relis la doc sur std::string::c_str(), c'est une valeur temporaire est contrôlé par std::string. Quand std::string est modifié, ce pointeur ne doit plus être utilisé.
    La destruction d'un std::string est un changement d'état.

  3. #3
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2016
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Afghanistan

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Août 2016
    Messages : 11
    Par défaut
    Merci pour ta réponse.

    - Un usage abusif de pointeur là le bon sens voudrait une référence
    Je pensais que pointeur et référence voulaient dire la même chose. Dans le cas présent, mon bon sens me disait de passer des adresses en paramètres d'une fonction plutôt que la variable. Et de ce que j'ai lu, un pointeur est une adresse. Je vais revoir ce point.

    - Vouloir manipuler des chaînes de caractères avec char*. Surtout quand l'origine est un std::string
    En amont, je reçois un std::string, cela je ne peux rien y changer. En revanche, pour stocker les chaînes de caractères, je préférais utiliser un tableau de char* plutôt qu'un tableau de string car je pensais que c'était moins couteux en mémoire. Qu'en penses-tu ?

    Concernant std::string::c_str(), j'ai lu qu'il s'agissait d'un pointeur vers la chaîne de caractères correspondant au string déclaré avec le caractère nul à la fin. Tu me dis qu'il ne faut plus utiliser ce pointeur quand std::string est modifié. Dans mon cas, puisqu'on est dans une fonction, je pense qu'à la fin de son exécution, le string toto est détruit. Mais j'accède au pointeur avant la destruction du string toto donc je ne comprends pas ?

  4. #4
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par défaut
    Citation Envoyé par jamesandrew Voir le message
    En revanche, pour stocker les chaînes de caractères, je préférais utiliser un tableau de char* plutôt qu'un tableau de string car je pensais que c'était moins couteux en mémoire.
    Dans ce cas, au moins, remplace vector<char*> par vector<const char*> et supprime les const_cast<char*>.

    char*, et donc aussi vector<char*>, permet de modifier le contenu d'une chaîne.
    Mais si le programme a stocké la chaîne dans une zone mémoire accessible uniquement en lecture, alors tenter de la modifier fera probablement crasher le programme.

    Hélas, en C++98, les constantes littérales comme "Hello" sont convertibles en char*, par rétrocompatibilité avec le C. Mais cette anomalie est corrigée en C++11. Ainsi, le code suivant ne compilera plus en C++11 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void fct_test(vector<char*> *listref)
    {
    	(*listref).push_back("Hello");
    }
    Citation Envoyé par jamesandrew Voir le message
    Dans mon cas, puisqu'on est dans une fonction, je pense qu'à la fin de son exécution, le string toto est détruit. Mais j'accède au pointeur avant la destruction du string toto donc je ne comprends pas ?
    Lors de la destruction de toto, la mémoire contenant la chaîne de caractères pointée par toto.c_str() est libérée.
    Le fait d'avoir copié quelque part ailleurs l'adresse vers cette chaîne de caractères n'empêche pas cette libération.

    Si tu veux persister à utiliser std::vector<const char*> :
    • Tu peux faire push_back sur une constante littérale, par exemple myVector.push_back("Hello"). Ce n'est pas dangereux car ces chaînes sont allouées pour toute la durée de l'exécution du programme.
    • Si tu fais myVector.push_back(objetStdString.c_str()), ça va être sportif. Je conseille alors que objetStdString soit de type const std::string. Comme ça, tu n'auras plus à te soucier que objetStdString ne soit pas modifié en cours de vie, mais "seulement" qu'il ne soit pas détruit trop tôt.


    Cependant, à moins que la performance soit un critère crucial de ton programme, je conseille vivement de préférer std::vector<std::string>. La chaîne sera copiée à chaque insertion* mais, au moins, il n'y aura plus de risque de pointer vers une chaîne détruite.

    * : Sauf si l'implémentation de std::string utilise le Copy On Write, mais c'est une autre histoire.

  5. #5
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    Citation Envoyé par Pyramidev Voir le message
    * : Sauf si l'implémentation de std::string utilise le Copy On Write, mais c'est une autre histoire.
    Ou que le constructeur de déplacement soit utilisé. Surtout que si je comprends bien, la chaîne existe toujours et va être stockée dans le vecteur quoi qu'il arrive. Il y a tout intérêt à utiliser un vecteur de std::string et std::move dans cette situation.

  6. #6
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2016
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Afghanistan

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Août 2016
    Messages : 11
    Par défaut
    C'est bon j'ai compris mes erreurs sur les pointeurs, j’utilise maintenant un vecteur de string et ça marche très bien. Merci beaucoup

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

Discussions similaires

  1. Problème pour parcourir une liste de String
    Par Invité dans le forum Débuter avec Java
    Réponses: 13
    Dernier message: 21/07/2010, 18h31
  2. Réponses: 4
    Dernier message: 26/12/2009, 20h48
  3. Réponses: 8
    Dernier message: 03/12/2006, 17h46
  4. passage par référence d'un buffer de type String
    Par youp_db dans le forum Langage
    Réponses: 2
    Dernier message: 11/10/2006, 10h51
  5. Réponses: 4
    Dernier message: 26/12/2005, 17h01

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