¿Cuál es la vida útil del resultado de std::string::c_str()?

Resuelto ereOn asked hace 13 años • 7 respuestas

En uno de mis programas, tengo que interactuar con algún código heredado que funcione con const char*.

Digamos que tengo una estructura que se parece a:

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

Mi aplicación de nivel superior solo trata con std::string, así que pensé en usarla std::string::c_str()para recuperar const char*punteros.

¿ Pero cuál es la vida útil de c_str()?

¿Puedo hacer algo como esto sin enfrentar un comportamiento indefinido?

{
  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
}

¿O se supone que debo copiar inmediatamente el resultado c_str()a otro lugar?

ereOn avatar Jun 23 '11 22:06 ereOn
Aceptado

El c_str()resultado deja de ser válido si se std::stringdestruye o si se llama a una función miembro no constante de la cadena. Por lo tanto, normalmente querrás hacer una copia si necesitas conservarla.

En el caso de su ejemplo, parece que los resultados de c_str()se usan de manera segura, porque las cadenas no se modifican mientras están en ese alcance. (Sin embargo, no sabemos qué use_foo()o ~Foo()podríamos estar haciendo con esos valores; si copian las cadenas en otro lugar, entonces deberían hacer una copia verdadera , y no solo copiar los charpunteros).

Kristopher Johnson avatar Jun 23 '2011 15:06 Kristopher Johnson

Técnicamente tu código está bien.

PERO ha escrito de tal manera que sea fácil de descifrar para alguien que no conozca el código. Para c_str() el único uso seguro es cuando lo pasas como parámetro a una función. De lo contrario, se expone a problemas de mantenimiento.

Ejemplo 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
}

Entonces, para el mantenimiento, hazlo obvio:

Mejor solución:

{
  // 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);    
}

Pero si tienes cadenas constantes, en realidad no las necesitas:

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

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

  use_foo(foo);
}

DE ACUERDO. Por alguna razón, los quiere como cadenas: ¿
por qué no usarlos solo en la llamada?

{
  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());
}
Martin York avatar Jun 23 '2011 16:06 Martin York

Es válido hasta que ocurra una de las siguientes situaciones con el stringobjeto correspondiente:

  • el objeto es destruido
  • el objeto se modifica

Está bien con su código a menos que modifique esos stringobjetos después c_str()de copiarlos foopero antes de use_foo()llamarlos.

sharptooth avatar Jun 23 '2011 15:06 sharptooth

El valor de retorno de c_str() es válido solo hasta la siguiente llamada de una función miembro no constante para la misma cadena

DumbCoder avatar Jun 23 '2011 15:06 DumbCoder