Bedeutet “&s[0]” auf zusammenhängende Zeichen in einem std::string zeigen?

Lesezeit: 4 Minuten

Bedeutet s0 auf zusammenhangende Zeichen in einem stdstring zeigen
paxos1977

Ich mache einige Wartungsarbeiten und bin auf etwas wie das Folgende gestoßen:

std::string s;
s.resize( strLength );  
// strLength is a size_t with the length of a C string in it. 

memcpy( &s[0], str, strLength );

Ich kenne die Verwendung von &s[0] wäre sicher, wenn es ein std::vector wäre, aber ist dies eine sichere Verwendung von std::string?

  • Die Verwendung von &s[0] ist in Ordnung, memcpy() wohl weniger. Warum führen Sie nicht einfach eine Zuweisung durch oder verwenden die Member-Funktion assign() des Strings?

    anon

    31. Dezember 2009 um 20:26 Uhr


  • @Neil Butterworth, das frage ich mich, wenn ich mir diesen Code ansehe … 😉

    – paxos1977

    31. Dezember 2009 um 20:29 Uhr

  • Je mehr Erfahrung Sie mit der Programmierung in C++ sammeln, desto mehr verzichten Sie auf die Verwendung von memset und memcpy, und lernen Sie die Argumentation. Dies ist eine, die Sie zu Ihrer Erfahrung hinzufügen können.

    – Thomas Matthäus

    31. Dezember 2009 um 21:30 Uhr

Bedeutet s0 auf zusammenhangende Zeichen in einem stdstring zeigen
Tod Gardner

Die Zuordnung eines std::string ist unter dem C++98/03-Standard nicht garantiert zusammenhängend, aber C++11 erzwingt dies. In der Praxis weder ich noch Herb Sutter kennen eine Implementierung, die keinen zusammenhängenden Speicher verwendet.

Beachten Sie, dass die &s[0] Ding funktioniert garantiert immer nach dem C++11-Standard, selbst im Fall von Zeichenfolgen der Länge 0. Es wäre nicht garantiert, wenn Sie dies tun würden str.begin() oder &*str.begin()aber für &s[0] die Norm definiert operator[] als:

Kehrt zurück: *(begin() + pos) wenn pos < size()andernfalls ein Verweis auf ein Objekt vom Typ T mit Wert charT(); der referenzierte Wert darf nicht verändert werden

Fortsetzung auf, data() ist definiert als:

Kehrt zurück: Ein Zeiger p so dass p + i == &operator[](i) für jeden i in [0,size()].

(beachten Sie die eckigen Klammern an beiden Enden des Bereichs)


Notiz: Vorstandardisierung C++0x hat nicht garantiert &s[0] mit Zeichenfolgen der Länge Null zu arbeiten (eigentlich war es ein explizit undefiniertes Verhalten), und eine ältere Überarbeitung dieser Antwort erklärte dies; Dies wurde in späteren Standardentwürfen behoben, daher wurde die Antwort entsprechend aktualisiert.

  • Ich habe den Standard in den letzten Monaten nicht befolgt, aber ich hatte den Eindruck, dass dies noch im 0x-Entwurf war und daher noch nicht erforderlich ist (oder werden wird, wenn eine Bibliothek nur ’03 implementiert).

    – Todd Gardner

    31. Dezember 2009 um 20:37 Uhr

  • Sutter sagt in einem Kommentar zu diesem Beitrag: „Aktuelles ISO C++ erfordert &str[0] um einen Zeiger auf zusammenhängende Zeichenfolgendaten (aber nicht unbedingt nullterminiert!) Auszuhusten, “was die Verwendung des OP tatsächlich korrekt machen würde. Ich kann jedoch nichts finden, was das im Standard sagt (zumindest ist es nicht in 21.3.4 lib.string.access).

    – James McNellis

    31. Dezember 2009 um 20:37 Uhr

  • Ich denke, das könnte richtig sein; der Standardfehler 530 sagt Bediener[] ist zusammenhängend, aber das Iterator-Interface ist nicht garantiert, und zitiert 23.4.4. Ich grabe meinen Standard aus, um ihn zu überprüfen.

    – Todd Gardner

    31. Dezember 2009 um 20:47 Uhr

  • Ich habe den Fehlerlink in Sutters Beitrag direkt übersprungen, deshalb habe ich ihn übersehen. In jedem Fall sagt der Fehler “wir benötigen schon fast Kontiguität” (Schlüsselwort: fast) und ich sehe nicht, wie sein Verweis auf Multiset relevant ist (basic_string ist eine Sequenz mit Iteratoren mit wahlfreiem Zugriff). Ich denke jedoch, dass es wichtig ist, dass “angesichts der Existenz von data() und der Definition von operator[] und was die Daten betrifft, glaube ich nicht, dass es möglich ist, einen nützlichen und standardkonformen basic_string zu schreiben, der nicht zusammenhängend ist.”

    – James McNellis

    31. Dezember 2009 um 21:11 Uhr

  • James: das fast ist, weil das null für ist s[s.length()] muss nicht zusammenhängend sein. &s[n] + 1 == &s[n + 1] muss für alle n wo wahr sein 0 <= n < s.length() - 1. Die Forderung ist in 21.3.4/1 begraben s[n] muss dasselbe Objekt wie zurückgeben s.data()[n] (für n < length()) und data() müssen zusammenhängend sein.

    Roger Pate

    31. Dezember 2009 um 21:39 Uhr

Technisch gesehen nein, da std::string ist nicht erforderlich, seinen Inhalt zusammenhängend im Speicher zu speichern.

In fast allen Implementierungen (jeder Implementierung, die mir bekannt ist) werden die Inhalte jedoch zusammenhängend gespeichert, und dies würde “funktionieren”.

  • Können Sie einige Implementierungen identifizieren, bei denen es nicht funktionieren würde?

    – Rob Kennedy

    31. Dezember 2009 um 20:25 Uhr

  • Nö. Aber Sie könnten eine solche Implementierung vornehmen, wenn Sie wollten.

    – James McNellis

    31. Dezember 2009 um 20:25 Uhr

  • @Neil: Hast du einen Link/Verweis zu diesem TC?

    – James McNellis

    31. Dezember 2009 um 20:35 Uhr

  • Aargh – Entschuldigung, Gehirn geht – ich denke an Vektor, nicht an String. Entschuldigung rundum.

    anon

    31. Dezember 2009 um 20:39 Uhr

  • Kein Problem. Ich bin immer noch neugierig, wovon Sutter spricht &str[0]obwohl (vgl. meinen Kommentar zu Todds Antwort).

    – James McNellis

    31. Dezember 2009 um 20:42 Uhr

1646709015 407 Bedeutet s0 auf zusammenhangende Zeichen in einem stdstring zeigen
Sebkrämer

Es ist sicher zu verwenden. Ich denke, die meisten Antworten waren einmal richtig, aber der Standard hat sich geändert. Zitieren aus dem C ++ 11-Standard, basic_string allgemeine Anforderungen [string.require]21.4.1.5, sagt:

Die char-ähnlichen Objekte in einem basic_string-Objekt müssen zusammenhängend gespeichert werden. Das heißt, für jedes basic_string-Objekt s soll die Identität &*(s.begin() + n) == &*s.begin() + n für alle Werte von n gelten, so dass 0 <= n < s.size ().

Etwas davor heißt es, dass alle Iteratoren Random-Access-Iteratoren sind. Beide Bits unterstützen die Verwendung Ihrer Frage. (Außerdem verwendet Stroustrup es anscheinend in seinem neuesten Buch 😉 )

Es ist nicht unwahrscheinlich, dass diese Änderung in C++11 vorgenommen wurde. Ich meine mich zu erinnern, dass die gleiche Garantie damals für Vektor hinzugefügt wurde, was auch sehr nützlich wurde Daten() Zeiger mit dieser Version.

Ich hoffe, das hilft.

  • Die Frage war vor c++11 (sie ist als solche gekennzeichnet). Sie haben Recht, c ++ 11 hat es offiziell sicher gemacht, dies zu tun.

    – paxos1977

    21. Januar 2015 um 20:08 Uhr


Bedeutet s0 auf zusammenhangende Zeichen in einem stdstring zeigen
John Dibling

Leser sollten beachten, dass diese Frage 2009 gestellt wurde, als der C++03-Standard die aktuelle Veröffentlichung war. Diese Antwort basiert auf der Version des Standards, in der std::strings sind nicht garantiert die Nutzung zusammenhängenden Speichers. Da diese Frage nicht im Zusammenhang mit einer bestimmten Plattform (wie gcc) gestellt wurde, mache ich keine Annahmen über die Plattform von OP – insbesondere, ob sie zusammenhängenden Speicher für die verwendet hat oder nicht string.

Gesetzlich? Vielleicht, vielleicht nicht. Sicher? Wahrscheinlich, aber vielleicht auch nicht. Guter Code? Nun, lass uns nicht dorthin gehen …

Warum nicht einfach:

std::string s = str;

…oder:

std::string s(str);

…oder:

std::string s;
std::copy( &str[0], &str[strLen], std::back_inserter(s));

…oder:

std::string s;
s.assign( str, strLen );

?

1646709017 511 Bedeutet s0 auf zusammenhangende Zeichen in einem stdstring zeigen
Ameise

Dies ist im Allgemeinen nicht sicher, unabhängig davon, ob die interne Saitenfolge dauerhaft gespeichert ist oder nicht. Es kann viele andere Implementierungsdetails geben, die sich darauf beziehen, wie die gesteuerte Sequenz gespeichert wird std::string Objekt, neben der Kontinuität.

Ein echtes praktisches Problem dabei könnte folgendes sein. Die kontrollierte Abfolge von std::string muss nicht als nullterminierter String gespeichert werden. In der Praxis entscheiden sich jedoch viele (die meisten?) Implementierungen dafür, den internen Puffer um 1 zu vergrößern und die Sequenz trotzdem als nullterminierte Zeichenfolge zu speichern, da dies die Implementierung von vereinfacht c_str() Methode: Geben Sie einfach einen Zeiger auf den internen Puffer zurück und Sie sind fertig.

Der Code, den Sie in Ihrer Frage zitiert haben, bemüht sich nicht, die Daten mit Null zu beenden, und sie werden in den internen Puffer kopiert. Möglicherweise weiß es einfach nicht, ob für diese Implementierung von Nullterminierung erforderlich ist std::string. Möglicherweise beruht es darauf, dass der interne Puffer nach dem Aufruf von mit Nullen gefüllt wird resize, so dass das zusätzliche Zeichen, das von der Implementierung für das Null-Terminator zugewiesen wird, praktischerweise auf Null voreingestellt ist. All dies ist ein Implementierungsdetail, was bedeutet, dass diese Technik von einigen ziemlich fragilen Annahmen abhängt.

Mit anderen Worten, in einigen Implementierungen müssten Sie wahrscheinlich verwenden strcpynicht memcpy die Daten so in die kontrollierte Reihenfolge zu zwingen. Während Sie in einigen anderen Implementierungen verwenden müssten memcpy und nicht strcpy.

  • Nach dem Anruf bei resize Sie können ziemlich sicher sein, dass die interne Zeichenfolge nullterminiert ist oder nicht, wie es die Implementierung erfordert. Nach einem Anruf bei resize Schließlich müssen Sie eine gültige Zeichenfolge mit n Zeichen haben (bei Bedarf mit Nullzeichen aufgefüllt). – Allerdings zeigt es Unverständnis für die std::string Klasse: memcpy wird entweder aus Unwissenheit oder als fehlgeleiteter Leistungsversuch (wegen der resize Der Aufruf des Codes führt dazu, dass dem Puffer zweimal Werte zugewiesen werden).

    – Onkel Bens

    31. Dezember 2009 um 23:23 Uhr

  • @UncleBens: Ich verstehe deinen ersten Satz nicht. In jedem Fall garantiert ja der Sprachstandard, dass die Größe zunimmt resize Call füllt die Zeichenfolge mit Nullen auf. Allerdings garantiert die Norm die Polsterung nur bis zur geforderten Größe (strLength in diesem Fall), aber es gibt im Standard keine Garantie für dieses zusätzliche Zeichen, wenn die Implementierung eines zuweist.

    – Ant

    31. Dezember 2009 um 23:28 Uhr

  • Ab C++11 ist der interne Puffer leer, wenn die Zeichenfolge nicht leer ist erforderlich nullterminiert sein, weil beides data() und c_str() sind erforderlich um denselben Puffer zurückzugeben, und c_str() ist erforderlich um immer einen Zeiger auf einen nullterminierten Puffer zurückzugeben (data() darf zurückkehren nullptr wenn leer). Vor C++11 war der interne Puffer nicht vorhanden erforderlich nullterminiert (oder sogar zusammenhängend) sein, aber die meisten Implementierungen waren, weil es die Implementierung von vereinfachte c_str()

    – Rémy Lebeau

    30. August 2019 um 22:56 Uhr


1646709017 351 Bedeutet s0 auf zusammenhangende Zeichen in einem stdstring zeigen
Clifford

Der Code könnte funktionieren, aber mehr Glück als Urteil macht er Annahmen über die Implementierung, die nicht garantiert sind. Ich schlage vor, dass die Bestimmung der Gültigkeit des Codes irrelevant ist, während es sich um eine sinnlose Überkomplikation handelt, die sich leicht auf Folgendes reduzieren lässt:

std::string s( str ) ;

oder wenn Sie einem vorhandenen std::string-Objekt zuweisen, einfach:

s = str ;

und lassen Sie dann std::string selbst bestimmen, wie das Ergebnis erreicht wird. Wenn Sie auf diese Art von Unsinn zurückgreifen, können Sie std::string genauso gut nicht verwenden und dabei bleiben, da Sie alle mit C-Strings verbundenen Gefahren wieder einführen.

  • Nach dem Anruf bei resize Sie können ziemlich sicher sein, dass die interne Zeichenfolge nullterminiert ist oder nicht, wie es die Implementierung erfordert. Nach einem Anruf bei resize Schließlich müssen Sie eine gültige Zeichenfolge mit n Zeichen haben (bei Bedarf mit Nullzeichen aufgefüllt). – Allerdings zeigt es Unverständnis für die std::string Klasse: memcpy wird entweder aus Unwissenheit oder als fehlgeleiteter Leistungsversuch (wegen der resize Der Aufruf des Codes führt dazu, dass dem Puffer zweimal Werte zugewiesen werden).

    – Onkel Bens

    31. Dezember 2009 um 23:23 Uhr

  • @UncleBens: Ich verstehe deinen ersten Satz nicht. In jedem Fall garantiert ja der Sprachstandard, dass die Größe zunimmt resize Call füllt die Zeichenfolge mit Nullen auf. Allerdings garantiert die Norm die Polsterung nur bis zur geforderten Größe (strLength in diesem Fall), aber es gibt im Standard keine Garantie für dieses zusätzliche Zeichen, wenn die Implementierung eines zuweist.

    – Ant

    31. Dezember 2009 um 23:28 Uhr

  • Ab C++11 ist der interne Puffer leer, wenn die Zeichenfolge nicht leer ist erforderlich nullterminiert sein, weil beides data() und c_str() sind erforderlich um denselben Puffer zurückzugeben, und c_str() ist erforderlich um immer einen Zeiger auf einen nullterminierten Puffer zurückzugeben (data() darf zurückkehren nullptr wenn leer). Vor C++11 war der interne Puffer nicht vorhanden erforderlich nullterminiert (oder sogar zusammenhängend) sein, aber die meisten Implementierungen waren, weil es die Implementierung von vereinfachte c_str()

    – Rémy Lebeau

    30. August 2019 um 22:56 Uhr


971540cookie-checkBedeutet “&s[0]” auf zusammenhängende Zeichen in einem std::string zeigen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy