it-swarm.com.de

string.c_str () Freigabe notwendig?

Mein Code wandelt C++ - Zeichenfolgen häufig in CStrings um, und ich frage mich, ob die ursprüngliche Zeichenfolge dem Stapel zugewiesen ist. Wird die CString-Zeichenfolge auch dem Stapel zugewiesen? Zum Beispiel:

string s = "Hello world";
char* s2 = s.c_str();

Wird s2 auf dem Stack oder auf dem Heap zugewiesen? Mit anderen Worten, muss ich s2 löschen?

Umgekehrt, wenn ich diesen Code habe:

string s = new string("Hello, mr. heap...");
char* s2 = s.c_str();

Befindet sich s2 nun auf dem Haufen, da sein Ursprung auf dem Haufen lag?

Um zu verdeutlichen, wenn ich frage, ob sich s2 auf dem Heap befindet, weiß ich, dass sich der Zeiger auf dem Stapel befindet. Ich frage, ob was darauf hindeutet auf dem Haufen oder auf dem Stapel liegen wird.

31
string s = "Hello world";
char* s2 = s.c_str();

Wird s2 auf dem Stack oder im Heap zugewiesen? Mit anderen Worten ... Muss ich s2 löschen?

Nein, nicht delete s2!

s2 befindet sich auf dem Stapel, wenn der obige Code in einer Funktion enthalten ist; Wenn der Code im globalen Bereich oder Namespace-Bereich liegt, befindet sich s2 in einem statisch zugewiesenen dynamisch initialisierten Datensegment. In jedem Fall handelt es sich um einen Zeiger auf ein Zeichen (das in diesem Fall das erste 'H'-Zeichen in der ASCIIZ-Darstellung des Textinhalts von s ist). Dieser Text selbst ist überall dort, wo das s-Objekt das Gefühl hatte, diese Repräsentation zu konstruieren. Implementierungen dürfen dies zwar tun, was sie möchten, aber die entscheidende Implementierungsentscheidung für std::string ist, ob sie eine "Kurzzeichenfolgenoptimierung" bereitstellt, mit der sehr kurze Zeichenfolgen direkt in das s-Objekt eingebettet werden können und ob "Hello world" kurz genug ist, um davon zu profitieren diese Optimierung:

  • wenn ja, würde s2 auf den Speicher innerhalb von s verweisen, der stapel- oder statisch zugewiesen wird, wie oben für s2 erläutert
  • andernfalls würde sich in s ein Zeiger auf dynamisch zugewiesenen Speicher (Freispeicher/Heap-Speicher) befinden, in dem der Inhalt "Hello world\0", dessen Adresse von .c_str() zurückgegeben wird, angezeigt wird und s2 eine Kopie dieses Zeigerwerts wäre.

Beachten Sie, dass c_str()const ist, damit Sie den Code kompilieren können, müssen Sie const char* s2 = ... ändern.

Sie darf nichtdelete s2. Die Daten, zu denen s2 Punkte gehört und von denen das Objekt s verwaltet wird, werden durch jeden Aufruf von non -const-Methoden von s oder durch s ungültig gemacht.

string s = new string("Hello, mr. heap...");
char* s2 = s.c_str();

Wird s2 jetzt auf dem Haufen sein, da der Ursprung auf dem Haufen lag?

Dieser Code kann nicht kompiliert werden, da s kein Zeiger ist und ein String keinen Konstruktor wie string(std::string*) hat. Sie können es ändern in:

string* s = new string("Hello, mr. heap...");

...oder...

string s = *new string("Hello, mr. heap...");

Letzteres erzeugt einen Speicherverlust und dient keinem nützlichen Zweck. Nehmen wir also erstere an. Dann:

char* s2 = s.c_str();

... muss werden ...

char* s2 = s->c_str();

Wird s2 jetzt auf dem Haufen sein, da der Ursprung auf dem Haufen lag?

Ja. In allen Szenarien, insbesondere wenn sich s selbst auf dem Heap befindet, gilt Folgendes:

  • auch wenn sich in s ein kurzer String-Optimierungspuffer befindet, auf den c_str() einen Zeiger gibt, muss er sich auf dem Heap befinden, andernfalls
  • wenn s einen Zeiger auf weiteren Speicher verwendet, um den Text zu speichern, wird dieser Speicher ebenfalls aus dem Heapspeicher zugewiesen.

Auch wenn Sie sicher sind, dass s2 auf von dem Heap zugewiesenen Speicher verweist, muss Ihr Code diesen Speicher nicht freigeben. Er wird automatisch ausgeführt, wenn s gelöscht wird:

string* s = new string("Hello, mr. heap...");
const char* s2 = s->c_str();
...use s2 for something...
delete s;   // "destruct" s and deallocate the heap used for it...

Natürlich ist es in der Regel besser, string s("xyz"); zu verwenden, es sei denn, Sie benötigen eine Lebensdauer außerhalb des lokalen Bereichs und andernfalls einen std::unique_ptr<std::string> oder std::shared_ptr<std::string>.

36
Tony Delroy

c_str() gibt einen Zeiger auf einen internen Puffer im string -Objekt zurück - free()/delete it.

Es ist nur gültig, solange das string, in das es zeigt, im Gültigkeitsbereich ist. Wenn Sie außerdem eine non-const-Methode des string -Objekts aufrufen, ist die Gültigkeit nicht mehr garantiert. 

http://www.cplusplus.com/reference/string/string/c_str/

(Aus Gründen der Klarheit aufgrund der nachstehenden Kommentare bearbeitet)  

14
Brian Roach

std::string::c_str() gibt einen const char* zurück, nicht einen char *. Das ist ein ziemlich guter Hinweis darauf, dass Sie ihn nicht freigeben müssen. Der Speicher wird von der Instanz verwaltet (siehe einige Details in this link ). Er ist also nur gültig, solange die String-Instanz gültig ist.

4
vanza

Erstens ist selbst Ihre ursprüngliche Zeichenfolge nicht auf dem Stapel zugewiesen, wie Sie zu glauben scheinen. Zumindest nicht ganz. Wenn Ihr string s als lokale Variable deklariert ist, wird nur das string-Objekt selbst "auf dem Stack" zugewiesen. Die kontrollierte Sequenz dieses String-Objekts wird an anderer Stelle zugewiesen. Sie sollen nicht wissen, wo sie zugewiesen werden, aber in den meisten Fällen wird sie auf dem Heap zugewiesen. Das heißt Die tatsächliche Zeichenfolge "Hello world", die in Ihrem ersten Beispiel von s gespeichert wurde, wird im Allgemeinen auf dem Heapspeicher zugewiesen, unabhängig davon, wo Sie Ihre s deklarieren.

Zweitens über c_str().

In der ursprünglichen Spezifikation von C++ (C++ 98) gab c_str im Allgemeinen einen Zeiger auf einen unabhängigen Puffer zurück, der irgendwo zugewiesen wurde. Sie sollten wiederum nicht wissen, wo sie zugewiesen werden, aber im Allgemeinen sollte sie auf dem Heap zugewiesen werden. Die meisten Implementierungen von std::string stellten sicher, dass ihre kontrollierte Sequenz immer nullterminiert war, sodass ihr c_str einen direkten Zeiger auf die kontrollierte Sequenz zurückgab.

In der neuen Spezifikation von C++ (C++ 11) ist es nun erforderlich, dass c_str einen direkten Zeiger auf die gesteuerte Sequenz zurückgibt.

Mit anderen Worten, im Allgemeinen wird das Ergebnis von c_str auch für lokale std::string-Objekte auf einen vom Speicher zugewiesenen Speicher zeigen. Ihr erstes Beispiel unterscheidet sich in diesem Punkt nicht von Ihrem zweiten Beispiel. In jedem Fall gehört der Speicher, auf den c_str() zeigt, nicht Ihnen. Sie sollten es nicht freigeben. Sie sollen nicht einmal wissen, wo sie zugeteilt werden.

4
AnT

s2 ist gültig, solange s im Gültigkeitsbereich bleibt. Es ist ein Zeiger auf Speicher, den s besitzt. Siehe z.B. diese MSDN-Dokumentation : "die Zeichenfolge hat eine begrenzte Lebensdauer und gehört der Klassenzeichenfolge."

Wenn Sie std::string in einer Funktion als Factory für die Zeichenfolgenbearbeitung verwenden und dann Zeichenfolgen im Stil c zurückgeben möchten, müssen Sie Heapspeicher für den Rückgabewert zuordnen. Holen Sie sich Speicherplatz mit malloc oder new und kopieren Sie dann den Inhalt von s.c_str().

2
japreiss

Wird s2 auf dem Stack oder im Heap zugewiesen?

Könnte in entweder sein. Wenn die std::string-Klasse beispielsweise eine Optimierung für kleine Zeichenfolgen durchführt, befinden sich die Daten auf dem Stapel, wenn ihre Größe unter dem SSO-Schwellenwert liegt, und ansonsten auf dem Heap. (Und dies alles setzt voraus, dass sich das std::string-Objekt selbst auf dem Stapel befindet.)

Muss ich s2 löschen?

Nein, das von c_str zurückgegebene Zeichenarrayobjekt gehört dem String-Objekt.

Wird s2 jetzt auf dem Haufen sein, da der Ursprung auf dem Haufen lag?

In diesem Fall befinden sich die Daten wahrscheinlich auch im SSO im Heap. Es gibt jedoch selten einen Grund, ein std::string-Objekt dynamisch zuzuweisen.

Kommt darauf an. Wenn ich mich recht erinnere, erstellt CString eine Kopie der Eingabezeichenfolge. Nein, Sie benötigen keine speziellen Heap-Zuweisungsroutinen. 

0
Chris K