web-dev-qa-db-fra.com

Quelle est la durée de vie de std :: string :: c_str ()?

Dans l'un de mes programmes, je dois interfacer avec du code hérité qui fonctionne avec const char*.

Disons que j'ai une structure qui ressemble à:

struct Foo
{
  const char* server;
  const char* name;
};

Mon application de niveau supérieur ne traite que de std::string, J'ai donc pensé à utiliser std::string::c_str() pour récupérer const char* Pointeurs.

Mais quelle est la durée de vie de c_str()?

Puis-je faire quelque chose comme ça sans faire face à un comportement indéfini?

{
  std::string server = "my_server";
  std::string name = "my_name";

  Foo foo;
  foo.server = server.c_str();
  foo.name = name.c_str();

  // We use foo
  use_foo(foo);

  // Foo is about to be destroyed, before name and server
}

Ou suis-je censé copier immédiatement le résultat de c_str() vers un autre endroit?

Merci.

90
ereOn

Le résultat c_str() devient invalide si le std::string Est détruit ou si une fonction membre non const de la chaîne est appelée. Donc, généralement, vous voudrez en faire une copie si vous avez besoin de le garder.

Dans le cas de votre exemple, il semble que les résultats de c_str() sont utilisés en toute sécurité, car les chaînes ne sont pas modifiées dans cette étendue. (Cependant, nous ne savons pas ce que use_foo() ou ~Foo() pourraient faire avec ces valeurs; s'ils copient les chaînes ailleurs, alors ils devraient faire un vrai copier, et pas seulement copier les pointeurs char.)

80
Kristopher Johnson

Techniquement, votre code est correct.

MAIS vous avez écrit d'une manière qui facilite la rupture pour quelqu'un qui ne connaît pas le code. Pour c_str (), la seule utilisation sûre est lorsque vous la transmettez en tant que paramètre à une fonction. Sinon, vous vous ouvrez à des problèmes de maintenance.

Exemple 1:

{
  std::string server = "my_server";
  std::string name   = "my_name";

  Foo foo;
  foo.server = server.c_str();
  foo.name = name.c_str();

  //
  // Imagine this is a long function
  // Now a maintainer can easily come along and see name and server
  // and would never expect that these values need to be maintained as
  // const values so why not re-use them

  name += "Martin";
  // Oops now its broken.

  // We use foo
  use_foo(foo);

  // Foo is about to be destroyed, before name and server
}

Donc, pour la maintenance, il est évident:

Meilleure solution:

{
  // Now they can't be changed.
  std::string const server = "my_server";
  std::string const name   = "my_name";

  Foo foo;
  foo.server = server.c_str();
  foo.name = name.c_str();

  use_foo(foo);    
}

Mais si vous avez des chaînes const, vous n'en avez pas réellement besoin:

{
  char const* server = "my_server";
  char const* name   = "my_name";

  Foo foo;
  foo.server = server;
  foo.name   = name;

  use_foo(foo);
}

D'ACCORD. Pour une raison quelconque, vous les voulez sous forme de chaînes:
Pourquoi ne pas les utiliser uniquement dans l'appel:

{
  std::string server = "my_server";
  std::string name = "my_name";

  // guaranteed not to be modified now!!!     
  use_foo(Foo(server.c_str(), name.c_str());
}
22
Martin York

Il est valide jusqu'à ce que l'une des situations suivantes se produise pour l'objet string correspondant:

  • l'objet est détruit
  • l'objet est modifié

Vous êtes d'accord avec votre code, sauf si vous modifiez ces objets string après que c_str() s sont copiés dans foo mais avant que use_foo() soit appelé.

7
sharptooth

La valeur de retour de c_str () n'est valide que jusqu'au prochain appel d'une fonction membre non constante pour la même chaîne

4
DumbCoder

Le const char* Renvoyé par c_str() n'est valide que jusqu'au prochain appel non const à l'objet std::string. Dans ce cas, tout va bien parce que votre std::string Est toujours à la portée de la vie de Foo et vous ne faites aucune autre opération qui changerait la chaîne lors de l'utilisation de foo.

3
AJG85

Pour être complet, voici un référence et citation de cppreference.com :

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

  • Passer une référence non const à la chaîne à n'importe quelle fonction de bibliothèque standard, ou
  • Appel de fonctions membres non const sur la fonction string, à l'exclusion de operator[], at(), front(), back(), begin(), rbegin(), end() et rend().
2
Victor Sergienko

Tant que la chaîne n'est pas détruite ou modifiée, l'utilisation de c_str () est OK. Si la chaîne est modifiée à l'aide d'un c_str () précédemment renvoyé, l'implémentation est définie.

2
CharlesB