Was ist die Lebensdauer von std :: string :: c_str ()?

100

In einem meiner Programme muss ich mit einem Legacy-Code arbeiten, mit dem funktioniert const char*.

Nehmen wir an, ich habe eine Struktur, die so aussieht:

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

Meine übergeordnete Anwendung befasst sich nur mit std::string, daher habe ich darüber nachgedacht std::string::c_str(), const char*Zeiger zurückzugewinnen.

Aber wie lange dauert es c_str()?

Kann ich so etwas tun, ohne mich einem undefinierten Verhalten zu stellen?

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

Oder soll ich das Ergebnis sofort c_str()an einen anderen Ort kopieren ?

Danke dir.

ereOn
quelle
Ist mir passiert, als ich eine lokale Zeichenfolge in einer Funktion definiert und zurückgegeben habe .c_str(). Ich habe nicht verstanden, warum ich manchmal nur Teile der Saite bekomme, bis ich verstanden habe, dass die const char*nicht für immer lebt, sondern bis die Saite zerstört ist
SomethingSomething

Antworten:

85

Das c_str()Ergebnis wird ungültig, wenn das std::stringzerstört wird oder wenn eine nicht konstante Mitgliedsfunktion der Zeichenfolge aufgerufen wird. Normalerweise möchten Sie also eine Kopie davon erstellen, wenn Sie sie behalten müssen.

In Ihrem Beispiel werden die Ergebnisse von c_str()sicher verwendet, da die Zeichenfolgen in diesem Bereich nicht geändert werden. (Wir wissen jedoch nicht, was use_foo()oder ~Foo()was mit diesen Werten geschehen könnte. Wenn sie die Zeichenfolgen an anderer Stelle kopieren , sollten sie eine echte Kopie erstellen und nicht nur die charZeiger kopieren .)

Kristopher Johnson
quelle
Der Zeiger c_str () kann ungültig sein, wenn das std :: string-Objekt ein automatisches Objekt ist, das den Gültigkeitsbereich verlässt oder eine Thread-Erstellungsfunktion aufruft.
GuruM
Kannst du das bitte erklären non-const member function of the string is called.?
Mathew Kurian
2
Eine "nicht konstante Mitgliedsfunktion" ist eine Mitgliedsfunktion, die nicht mit dem constSchlüsselwort gekennzeichnet ist. Eine solche Funktion kann den Inhalt der Zeichenfolge mutieren. In diesem Fall muss die Zeichenfolge möglicherweise den Speicher für die nullterminierte Version der von zurückgegebenen Zeichenfolge neu zuweisen c_str(). Zum Beispiel size()und length()sind const, so dass Sie sie aufrufen können, ohne sich Gedanken über die Änderung der Zeichenfolge machen zu müssen, dies clear()ist jedoch nicht der Fall const.
Kristopher Johnson
23

Technisch ist Ihr Code in Ordnung.

ABER Sie haben so geschrieben, dass es für jemanden, der den Code nicht kennt, leicht zu brechen ist. Für c_str () ist die einzige sichere Verwendung, wenn Sie es als Parameter an eine Funktion übergeben. Ansonsten öffnen Sie sich für Wartungsprobleme.

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

Machen Sie zur Wartung Folgendes klar:

Bessere Lösung:

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

Aber wenn Sie const Strings haben, brauchen Sie sie eigentlich nicht:

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

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

  use_foo(foo);
}

OK. Aus irgendeinem Grund möchten Sie sie als Zeichenfolgen:
Warum nicht nur im Aufruf verwenden:

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

Es ist gültig, bis eine der folgenden Aktionen mit dem entsprechenden stringObjekt ausgeführt wird:

  • Das Objekt wird zerstört
  • Das Objekt wird geändert

Ihr Code ist in Ordnung, es sei denn, Sie ändern diese stringObjekte, nachdem c_str()s in sie kopiert wurde, fooaber bevor sie use_foo()aufgerufen werden.

scharfer Zahn
quelle
4

Der Rückgabewert von c_str () ist nur bis zum nächsten Aufruf einer nicht konstanten Mitgliedsfunktion für dieselbe Zeichenfolge gültig

DumbCoder
quelle
3

Die const char*Rückgabe von c_str()ist nur bis zum nächsten nicht konstanten Aufruf des std::stringObjekts gültig . In diesem Fall geht es Ihnen gut, da Sie std::stringnoch ein Leben lang in Reichweite Foosind und Sie keine anderen Vorgänge ausführen, die die Zeichenfolge bei Verwendung von foo ändern würden.

AJG85
quelle
2

Solange die Zeichenfolge nicht zerstört oder geändert wird, ist die Verwendung von c_str () in Ordnung. Wenn der String mit einem zuvor zurückgegebenen c_str () geändert wird, ist die Implementierung definiert.

CharlesB
quelle
2

Der Vollständigkeit halber hier eine Referenz und ein Zitat von cppreference.com :

Der von erhaltene Zeiger c_str()kann ungültig gemacht werden durch:

  • Übergeben eines nicht konstanten Verweises auf die Zeichenfolge an eine Standardbibliotheksfunktion oder
  • Aufruf nicht konstante Mitgliederfunktionen auf das string, ohne operator[], at(), front(), back(), begin(), rbegin(), end()und rend().
Victor Sergienko
quelle