14 votes

string et const char* et .c_str() ?

Je rencontre un problème bizarre et je veux savoir pourquoi il se comporte ainsi. J'ai une classe dans laquelle il y a une fonction membre qui retourne std::string . Mon objectif est de convertir ce string a const char* J'ai donc fait ce qui suit

    const char* c;
    c = robot.pose_Str().c_str();  // is this safe??????
    udp_slave.sendData(c);

Le problème, c'est que j'ai un personnage bizarre du côté du maître. Cependant, si je fais ce qui suit

    const char* c;
    std::string data(robot.pose_Str());
    c = data.c_str();
    udp_slave.sendData(c);

Je reçois ce que j'attends. Ma question est la suivante : quelle est la différence entre les deux méthodes susmentionnées ?

19voto

Dov Points 1864

Il s'agit de pointer vers un temporaire. Si vous retournez par valeur mais que vous ne stockez pas l'objet string il disparaît au point de séquence suivant (le point-virgule).

Si vous le stockez dans une variable, alors le pointeur pointe vers quelque chose qui existe réellement pendant la durée de votre envoi par udp.

Considérez ce qui suit :

int f() { return 2; }

int*p = &f();

Cela semble stupide à première vue, n'est-ce pas ? Vous pointez sur une valeur qui est copiée à partir de f . Vous n'avez aucune idée de combien de temps il va vivre.

Su string c'est la même chose.

6voto

Rakib Points 5364

.c_str() renvoie l'adresse de l'objet char const* par valeur, ce qui signifie qu'il obtient une copie du pointeur. Mais après cela, le tableau de caractères réel vers lequel il pointe est détruit. C'est pourquoi vous obtenez des déchets. Dans le dernier cas, vous créez une nouvelle chaîne avec ce tableau de caractères en copiant les caractères de l'emplacement actuel. Dans ce cas, bien que le tableau de caractères soit détruit, la copie reste dans l'objet chaîne.

5voto

Rubens Points 6228

De c_str() :

Le pointeur obtenu par c_str() peut être invalidé par :

  • Transmission d'une référence non-const à la chaîne à une fonction de la bibliothèque standard, ou
  • Appel de fonctions membres non constantes sur la chaîne, à l'exclusion de operator[], at(), front(), back(), begin(), rbegin(), end() et rend().

Ce qui signifie que, si la chaîne retournée par robot.pose_Str() est détruit ou modifié par une fonction non-const, le pointeur vers la chaîne sera invalidé. Puisque vous pouvez renvoyer une copie temporaire à partir de robot.pose_Str() le retour de c_str() sur elle est invalide dès cet appel.

Pourtant, si vous renvoyez une référence à la chaîne interne que vous détenez, au lieu d'une copie temporaire, vous pouvez soit :

  • être sûr qu'il va fonctionner, dans le cas où votre fonction udp_send est synchrone ;
  • ou s'appuyer sur un pointeur non valide, et donc avoir un comportement non défini si udp_send peut se terminer après une éventuelle modification du contenu interne de la chaîne originale.

3voto

kec Points 1336

Vous ne pouvez pas utiliser les données pointées par c_str() après la durée de vie de la std::string objet d'où il vient. Parfois, la durée de vie n'est pas claire, comme dans le code ci-dessous. La solution est également indiquée :

#include <string>
#include <cstddef>
#include <cstring>

std::string foo() { return "hello"; }

char *
make_copy(const char *s) {
    std::size_t sz = std::strlen(s);
    char *p = new char[sz];
    std::strcpy(p, s);
    return p;
}

int
main() {
    const char *p1 = foo().c_str(); // Whoops, can't use p1 after this statement.
    const char *p2 = make_copy(foo().c_str()); // Okay, but you have to delete [] when done.
}

2voto

R Sahu Points 24027

Q

const char* c;
c = robot.pose_Str().c_str();  // is this safe??????
udp_slave.sendData(c);

A

C'est potentiellement dangereux. Cela dépend de ce que robot.pose_Str() retours. Si la durée de vie du retour std::string est plus longue que la durée de vie de c alors c'est sûr. Sinon, il ne l'est pas.

Vous stockez une adresse dans c qui sera invalide juste après la fin de l'exécution de l'instruction.

std::string s = robot.pose_Str();
const char* c = s.c_str();  // This is safe
udp_slave.sendData(c);

Ici, vous stockez une adresse dans c qui seront valables à l'unité où vous sortez du champ d'application dans lequel s y c sont définis.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X