Cos'è la durata di std :: string :: c_str ()?


100

In uno dei miei programmi, devo interfacciarmi con un codice legacy con cui funziona const char*.

Diciamo che ho una struttura che assomiglia a:

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

La mia applicazione di livello superiore si occupa solo di std::string, quindi ho pensato di utilizzare std::string::c_str()per tornare indietroconst char* puntatori.

Ma qual è la durata di c_str() ?

Posso fare qualcosa di simile senza dover affrontare un comportamento indefinito?

{
  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 dovrei copiare immediatamente il risultato di c_str()in un altro posto?

Grazie.


Mi è successo quando ho definito una stringa locale in una funzione e ho restituito .c_str(). Non ho capito perché a volte ricevo solo parti della stringa, fino a quando non ho capito che const char*non vive per sempre, ma fino a quando la stringa non viene distrutta
SomethingSomething

Risposte:


85

Il c_str()risultato non std::stringè più valido se viene eliminato o se viene chiamata una funzione membro non const della stringa. Quindi, di solito vorrai farne una copia se devi tenerla in giro.

Nel caso del tuo esempio, sembra che i risultati di c_str()vengono utilizzati in modo sicuro, perché le stringhe non vengono modificate in tale ambito. (Tuttavia, non sappiamo cosa use_foo()o ~Foo()potrebbe fare con quei valori; se copiano le stringhe altrove, dovrebbero fare una copia vera e non solo copiare i charpuntatori.)


Il puntatore c_str () potrebbe non essere valido se l'oggetto std :: string è un oggetto automatico che esce dall'ambito o in chiamata a una funzione di creazione di thread.
GuruM

Puoi spiegare per favore non-const member function of the string is called.?
Mathew Kurian

2
Una "funzione membro non const" è qualsiasi funzione membro non contrassegnata con la constparola chiave. Una tale funzione potrebbe modificare il contenuto della stringa, nel qual caso la stringa potrebbe dover riallocare la memoria per la versione con terminazione null della stringa restituita da c_str(). Ad esempio, size()e length()sono const, quindi puoi chiamarli senza preoccuparti del cambio di stringa, ma clear()non lo è const.
Kristopher Johnson

23

Tecnicamente il tuo codice va bene.

MA hai scritto in modo tale da rendere facile la violazione per qualcuno che non conosce il codice. Per c_str () l'unico utilizzo sicuro è quando lo si passa come parametro a una funzione. Altrimenti ti esponi a problemi di manutenzione.

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

Quindi per la manutenzione rendi ovvio:

Soluzione migliore:

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

Ma se hai stringhe const, in realtà non ne hai bisogno:

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

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

  use_foo(foo);
}

OK. Per qualche motivo li vuoi come stringhe:
perché non usarli solo nella chiamata:

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

7

È valido fino a quando non si verifica una delle seguenti condizioni stringall'oggetto corrispondente :

  • l'oggetto viene distrutto
  • l'oggetto viene modificato

Stai bene con il tuo codice a meno che non modifichi quegli stringoggetti dopo che c_str()s sono stati copiati fooma prima che use_foo()venga chiamato.


4

Il valore di ritorno di c_str () è valido solo fino alla successiva chiamata di una funzione membro non costante per la stessa stringa


3

Il valore const char*restituito da c_str()è valido solo fino alla successiva chiamata non const std::stringall'oggetto. In questo caso stai bene perché il tuo std::stringè ancora in ambito per la durata di Fooe non stai facendo altre operazioni che cambierebbero la stringa mentre usi foo.


2

Finché la stringa non viene distrutta o modificata, l'uso di c_str () è OK. Se la stringa viene modificata utilizzando un c_str () restituito in precedenza, viene definita l'implementazione.


2

Per completezza, ecco un riferimento e una citazione da cppreference.com :

Il puntatore ottenuto da c_str()può essere invalidato da:

  • Passaggio di un riferimento non const alla stringa a qualsiasi funzione della libreria standard o
  • Chiamare le funzioni di membro non-const su string, escludendo operator[], at(), front(), back(), begin(), rbegin(), end()e rend().
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.