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?

oompahloompah
quelle
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());
Greg
quelle
41

Ich denke du kannst es einfach tun

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

Dabei ist MyVector Ihr std :: vector.

LiMuBei
quelle
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()).

Ștefan
quelle
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.)

Martin Stone
quelle
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.

Randalieren
quelle
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.

Henri Raath
quelle
1
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());
TechCat
quelle
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