Co to jest okres istnienia std :: string :: c_str ()?


100

W jednym z moich programów muszę połączyć się z jakimś starszym kodem, który działa z const char*.

Powiedzmy, że mam strukturę, która wygląda następująco:

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

Moja aplikacja wyższego poziomu zajmuje się tylko tym std::string, więc pomyślałem o użyciu, std::string::c_str()aby odzyskać const char*wskaźniki.

Ale co to jest życie c_str()?

Czy mogę zrobić coś takiego, nie napotykając niezdefiniowanego zachowania?

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

A może mam od razu skopiować wynik w c_str()inne miejsce?

Dziękuję Ci.


Zdarzyło mi się, gdy zdefiniowałem lokalny ciąg w funkcji i wróciłem .c_str(). Nie rozumiałem, dlaczego czasami dostaję tylko części struny, dopóki nie zrozumiałem, że const char*nie żyje wiecznie, ale dopóki struna nie zostanie zniszczona
SomethingSomething

Odpowiedzi:


85

c_str()Wynik staje się nieważna, jeśli std::stringjest zniszczona lub jeśli funkcja członek non-const napisu jest tzw. Dlatego zazwyczaj będziesz chciał zrobić jego kopię, jeśli chcesz go zachować.

W przypadku naszego przykładu wygląda na to, że wyniki c_str()są używane bezpiecznie, ponieważ ciągi znaków nie są modyfikowane w tym zakresie. (Jednak nie wiemy, co use_foo()lub ~Foo()może robić z tymi wartościami; jeśli skopiują ciągi w innym miejscu, powinni wykonać prawdziwą kopię , a nie tylko skopiować charwskaźniki).


Wskaźnik c_str () może być nieprawidłowy, jeśli obiekt std :: string jest obiektem automatycznym wychodzącym poza zakres lub w wywołaniu funkcji tworzącej wątek.
GuruM

Czy możesz wyjaśnić non-const member function of the string is called.?
Mathew Kurian

2
„Funkcja składowa niebędąca stałą” to dowolna funkcja składowa, która nie jest oznaczona constsłowem kluczowym. Taka funkcja może zmodyfikować zawartość ciągu, w którym to przypadku ciąg może wymagać ponownego przydzielenia pamięci dla zakończonej znakiem null wersji ciągu zwróconego przez c_str(). Na przykład size()i length()const, więc możesz do nich dzwonić bez martwienia się o zmianę ciągu, ale clear()tak nie jest const.
Kristopher Johnson,

23

Technicznie rzecz biorąc, twój kod jest w porządku.

ALE napisałeś w taki sposób, że łatwo złamać komuś, kto nie zna kodu. Jedynym bezpiecznym użyciem c_str () jest przekazanie jej jako parametru do funkcji. W przeciwnym razie narażasz się na problemy z konserwacją.

Przykład 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
}

Więc jeśli chodzi o konserwację, to oczywiste:

Lepsze rozwiązanie:

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

Ale jeśli masz ciągi const, tak naprawdę ich nie potrzebujesz:

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

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

  use_foo(foo);
}

DOBRZE. Z jakiegoś powodu chcesz, aby były one ciągami:
Dlaczego nie używać ich tylko w wywołaniu:

{
  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

Jest ważny, dopóki jeden z poniższych warunków nie wystąpi z odpowiednim stringobiektem:

  • obiekt jest zniszczony
  • obiekt jest modyfikowany

Kod jest w porządku, chyba że zmodyfikujesz te stringobiekty po c_str()skopiowaniu s, fooale przed use_foo()wywołaniem.


4

Wartość zwracana c_str () jest ważna tylko do następnego wywołania niestałej funkcji składowej dla tego samego ciągu


3

Wartość const char*zwracana z c_str()jest ważna tylko do następnego wywołania std::stringobiektu niebędącego wartością stałą . W tym przypadku nic ci nie jest, ponieważ std::stringnadal znajdujesz się w zasięgu przez cały okres istnienia Fooi nie wykonujesz żadnych innych operacji, które zmieniłyby łańcuch podczas używania foo.


2

Dopóki łańcuch nie zostanie zniszczony ani zmodyfikowany, użycie c_str () jest OK. Jeśli ciąg zostanie zmodyfikowany przy użyciu zwróconej wcześniej c_str (), to jest zdefiniowana implementacja.


2

Aby uzyskać kompletność, oto odniesienie i cytat z cppreference.com :

Wskaźnik uzyskany z c_str()może zostać unieważniony przez:

  • Przekazywanie odwołania innego niż stała do ciągu do dowolnej standardowej funkcji bibliotecznej lub
  • Wywołanie funkcji const członka na string, z wyjątkiem operator[], at(), front(), back(), begin(), rbegin(), end()i rend().
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.