Wie erstelle ich einen std :: string aus einem std :: vector <char>?


115

Gibt es eine schnellere / alternative / "bessere" Möglichkeit, eine Zeichenfolge aus einem Zeichenvektor zu initialisieren, ohne (offensichtlich) zuerst eine Zeichenfolge im C-Stil zu erstellen und dann eine std :: Zeichenfolge zu erstellen?


4
Kann das ohne Kopieren gemacht werden? Mit anderen Worten, etwas, das dasselbe tut wie, std::vector<char> v2(std::move(v))aber mit einem std::stringals neuem Objekt.
tobi_s

Antworten:


197

Der beste Weg ist, den folgenden Konstruktor zu verwenden:

template<class InputIterator> string (InputIterator begin, InputIterator end);

was zu so etwas führen würde wie:

std::vector<char> v;
std::string str(v.begin(), v.end());

41

Ich denke du kannst es einfach tun

std::string s( MyVector.begin(), MyVector.end() );

Dabei ist MyVector Ihr std :: vector.


1
Außer in VS2013, das zur Laufzeit ungültige Iteratoren bestätigt, sofern Sie dies nicht festgelegt haben _ITERATOR_DEBUG_LEVEL=1(in diesem Fall scheint es einwandfrei zu funktionieren).
Cameron

35

Mit C ++ 11 können Sie std::string(v.data())oder, wenn Ihr Vektor '\0'am Ende kein enthält , , std::string(v.data(), v.size()).


Selbst mit C ++ 98 können Sie meiner Meinung nach std :: string (& v [0]) ausführen. Dies ist natürlich der Fall, wenn der Vektor nullterminiert ist.
Jamie

1
@Jamie: Übrigens sollte in C ++ 98 auch string(&v[0], v.size())funktionieren, aber erst danach assert(not v.empty());, da, wenn der Vektor leer ist, beide v[0]und v.front()undefiniertes Verhalten aufrufen würden. Abgesehen von der syntaktischen Einfachheit, den Address-of-Operator nicht verwenden zu müssen, ist dies der eigentliche Vorteil der data()Funktion von C ++ 11 , die auch auf einem leeren Vektor funktioniert.
Adam H. Peterson

Sehr richtig. Leider steckt mein Projekt auf absehbare Zeit in Visual Studio 2008 fest. Richtig, zuerst die Vektorlänge zu überprüfen.
Jamie

Wenn der Vektor kein '\ 0' enthält, führt dies std::string(v.data())möglicherweise zu einer längeren Zeichenfolge. Verwenden Sie diesen Weg also nicht.
HeLomaN

@heLomaN: Was ist los mit dem std::string(v.data(), v.size()), was in der Antwort genau aus diesem Grund ausdrücklich erwähnt wurde?
Gr.

12
std::string s(v.begin(), v.end());

Wobei v so ziemlich alles iterierbar ist. (Insbesondere begin () und end () müssen InputIterators zurückgeben.)


3

Der Vollständigkeit halber ist ein anderer Weg std::string(&v[0])(obwohl Sie sicherstellen müssen, dass Ihre Zeichenfolge nullterminiert ist und std::string(v.data())im Allgemeinen vorzuziehen ist.

Der Unterschied besteht darin, dass Sie die erstere Technik verwenden können, um den Vektor an Funktionen zu übergeben, die den Puffer ändern möchten, was mit .data () nicht möglich ist.


Warum können Sie data()den Puffer nicht ändern? Es sieht für mich so aus, als würde data()ein a-nicht konstanter Vektor a zurückgeben T *(und wenn Ihr Vektor const ist, würde 'v [0] ` T const &ohnehin a zurückgeben).
Adam H. Peterson

@ AdamH.Peterson es scheint ein Versehen im Standard zu sein. Die Daten von Std :: vector haben sowohl const- als auch non-const-Funktionen, während std :: string im aktuellen Standard nur eine const-Funktion hat: en.cppreference.com/w/cpp/string/basic_string/data Beachten Sie, dass C ++ 17 fügt eine nicht konstante Version hinzu, so dass dies möglicherweise nicht auf unbestimmte Zeit der Fall ist. Der aktuelle Standard besagt jedoch, dass das Ändern des Zeichenarrays, auf das über Daten zugegriffen wird, ein undefiniertes Verhalten aufweist.
Aufstand

Das wäre wahr, wenn ves eine Zeichenfolge wäre, aber der Zieltyp ist eine Zeichenfolge und vein Vektor. (Aber es ist schön zu sehen, dass C ++ 17 Strings Parität mit Vektor gibt.)
Adam H. Peterson

@ AdamH.Peterson du hast natürlich recht. Die Frage wurde vor einiger Zeit beantwortet. Ich hatte angenommen, dass es sich bei der gesamten Frage ausschließlich um Zeichenfolgen handelt, ohne dies zu überprüfen.
Aufstand

2

Ich mag Stefans Antwort (11. September 13), möchte sie aber etwas stärker machen:

Wenn der Vektor mit einem Nullterminator endet, sollten Sie nicht (v.begin (), v.end ()) verwenden: Sie sollten v.data () (oder & v [0] für diejenigen vor C ++ 17) verwenden. .

Wenn v keinen Nullterminator hat, sollten Sie (v.begin (), v.end ()) verwenden.

Wenn Sie begin () und end () verwenden und der Vektor eine abschließende Null hat, erhalten Sie beispielsweise eine Zeichenfolge "abc \ 0", die die Länge 4 hat, aber eigentlich nur "abc" sein sollte.


1
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());

Könnten Sie einige Erklärungen sowie den Code hinzufügen?
Paul Floyd

1
Die Vorlage für die C ++ 11-Zeichenfolgenbibliothek lautet wie folgt: default (1) string (); copy (2) string (const string & str); Teilzeichenfolge (3) Zeichenfolge (const Zeichenfolge & str, size_t pos, size_t len ​​= npos); von c-string (4) string (const char * s); aus Puffer (5) Zeichenfolge (const char * s, size_t n); fülle (6) string (size_t n, char c); Bereich (7) Template <Klasse InputIterator> String (InputIterator zuerst, InputIterator zuletzt); Zeichenfolge initializer list (8) (initializer_list <char> il); move (9) string (string && str) noexcept; Wir folgen der 7. Vorlage.
TechCat

Hallo @TechCat! Bitte lesen Sie eine gute Antwort, bevor Sie Ihre nächste Frage beantworten. Genießen Sie Ihren Aufenthalt im SO!
Diggy.

Könnten Sie bitte Ihre Antwort mit der Beschreibung bearbeiten?
Paul Floyd
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.