O que é std :: string :: c_str () lifetime?

100

Em um dos meus programas, tenho que fazer interface com algum código legado com o qual funciona const char*.

Digamos que tenho uma estrutura parecida com:

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

Meu aplicativo de nível superior lida apenas com std::string, então pensei em usar std::string::c_str()para obter const char*dicas de volta .

Mas qual é a vida útil de c_str()?

Posso fazer algo assim sem enfrentar um comportamento 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
}

Ou devo copiar imediatamente o resultado de c_str()para outro lugar?

Obrigado.

ereOn
fonte
Aconteceu comigo quando eu defini uma string local em uma função e retornei .c_str(). Não entendi porque às vezes recebo apenas partes do fio, até que entendi que o const char*não vive para sempre, mas até que o fio seja destruído
SomethingSomething

Respostas:

85

O c_str()resultado torna-se inválido se o std::stringfor destruído ou se uma função membro não const da string for chamada. Portanto, geralmente você desejará fazer uma cópia dele se precisar mantê-lo por perto.

No caso do seu exemplo, parece que os resultados de c_str()são usados ​​com segurança, porque as strings não são modificadas enquanto estão nesse escopo. (No entanto, não sabemos o que use_foo()ou podemos ~Foo()estar fazendo com esses valores; se eles copiarem as strings em outro lugar, eles devem fazer uma cópia verdadeira , e não apenas copiar os charponteiros.)

Kristopher Johnson
fonte
O ponteiro c_str () pode ser inválido se o objeto std :: string for um objeto automático saindo do escopo ou na chamada para uma função de criação de thread.
GuruM de
Você pode explicar non-const member function of the string is called.?
Mathew Kurian
2
Uma "função de membro não const" é qualquer função de membro que não esteja marcada com a constpalavra - chave. Tal função pode alterar o conteúdo da string, caso em que a string pode precisar realocar a memória para a versão terminada em nulo da string retornada por c_str(). Por exemplo, size()e length()são const, para que você possa chamá-los sem se preocupar com a mudança da string, mas clear()não é const.
Kristopher Johnson
23

Tecnicamente, seu código está bom.

MAS você escreveu de uma forma que torna mais fácil quebrá-lo para alguém que não conhece o código. Para c_str (), o único uso seguro é quando você o passa como um parâmetro para uma função. Caso contrário, você se expõe a problemas de manutenção.

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

Portanto, para manutenção, deixe-o óbvio:

Melhor solução:

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

Mas se você tiver strings const, na verdade não precisa delas:

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

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

  use_foo(foo);
}

ESTÁ BEM. Por algum motivo, você os quer como strings:
Por que não usá-los apenas na chamada:

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

É válido até que um dos seguintes aconteça com o stringobjeto correspondente :

  • o objeto está destruído
  • o objeto é modificado

Você está bem com o seu código, a menos que modifique esses stringobjetos após c_str()s serem copiados, foomas antes de use_foo()ser chamado.

dente afiado
fonte
4

O valor de retorno de c_str () é válido apenas até a próxima chamada de uma função de membro não constante para a mesma string

DumbCoder
fonte
3

O const char*retornado de c_str()só é válido até a próxima chamada não const para o std::stringobjeto. Neste caso, você está bem porque seu std::stringainda está no escopo por toda a vida de Fooe você não está fazendo nenhuma outra operação que alteraria a string ao usar foo.

AJG85
fonte
2

Contanto que a string não seja destruída ou modificada, usar c_str () está OK. Se a string for modificada usando um c_str () retornado anteriormente, a implementação é definida.

CharlesB
fonte
2

Para completar, aqui está uma referência e citação de cppreference.com :

O ponteiro obtido de c_str()pode ser invalidado por:

  • Passar uma referência não const à string para qualquer função de biblioteca padrão ou
  • Chamando funções de membro não-const na string, excluindo operator[], at(), front(), back(), begin(), rbegin(), end()e rend().
Victor Sergienko
fonte