¿Qué es std::string::c str() lifetime?


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 usar std::string::c_str() para obtener const char* punteros.

Pero ¿cuál es la vida 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 de c_str() a otro lugar ?

Gracias.

Author: ereOn, 2011-06-23

6 answers

El resultado c_str() no es válido si se destruye el std::string o si se llama a una función no miembro de const de la cadena. Por lo tanto, por lo general, usted querrá hacer una copia de ella si usted necesita mantenerlo alrededor.

En el caso de su ejemplo, parece que los resultados de c_str() se utilizan de forma segura, porque las cadenas no se modifican mientras están en ese ámbito. (Sin embargo, no sabemos lo que use_foo() o ~Foo() podría estar haciendo con esos valores; si copian las cadenas en otro lugar, entonces deberían hacer un verdadero copie, y no solo copie los punteros char.)

 74
Author: Kristopher Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-14 20:49:42

Técnicamente tu código está bien.

PERO has escrito de tal manera que hace que sea fácil de romper para alguien que no conoce el código. Para c_str () el único uso seguro es cuando se pasa como parámetro a una función. De lo contrario, se abre a los 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
}

Así que para el mantenimiento que sea 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 de const no necesitas [5]]}

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

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

  use_foo(foo);
}

OK. Por alguna razón las quieres 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());
}
 21
Author: Martin York,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-23 16:07:16

Es válido hasta que una de las siguientes situaciones le ocurra al objeto string correspondiente:

  • el objeto se destruye
  • el objeto se modifica

Está bien con su código a menos que modifique esos objetos string después de que c_str() se copien en foo pero antes de que se llame use_foo().

 6
Author: sharptooth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-23 15:15:23

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

 4
Author: DumbCoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-23 15:15:11

El const char* devuelto desde c_str() solo es válido hasta la siguiente llamada no constante al objeto std::string. En este caso, está bien porque su std::string todavía está en el alcance durante la vida útil de Foo y no está haciendo ninguna otra operación que cambie la cadena mientras usa foo.

 3
Author: AJG85,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-23 15:18:04

Mientras la cadena no sea destruida o modificada, usar c_str() está bien. Si la cadena se modifica usando una c_str() devuelta previamente se define la implementación.

 2
Author: CharlesB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-23 15:15:07