Comment construire un std :: string à partir d'un std :: vector <char>?

115

À part (ce qui est évident), construire d'abord une chaîne de style C puis l'utiliser pour créer une chaîne std :: string, existe-t-il un moyen plus rapide / alternatif / "meilleur" d'initialiser une chaîne à partir d'un vecteur de caractères?

oompahloompah
la source
4
Cela peut-il être fait sans copier? En d'autres termes, quelque chose qui fait la même chose que std::vector<char> v2(std::move(v))mais avec a std::stringcomme nouvel objet.
tobi_s

Réponses:

197

Eh bien, le meilleur moyen est d'utiliser le constructeur suivant:

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

ce qui conduirait à quelque chose comme:

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

Je pense que tu peux juste faire

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

où MyVector est votre std :: vector.

LiMuBei
la source
1
Sauf dans VS2013 qui affirme lors de l'exécution sur les itérateurs non valides, sauf si vous définissez _ITERATOR_DEBUG_LEVEL=1(auquel cas cela semble fonctionner correctement).
Cameron
35

Avec C ++ 11, vous pouvez faire std::string(v.data())ou, si votre vecteur ne contient pas de a '\0'à la fin std::string(v.data(), v.size()),.

Ștefan
la source
Même avec C ++ 98, je crois que vous pouvez faire std :: string (& v [0]). Ceci, bien sûr, si le vecteur est terminé par un nul.
Jamie
1
@Jamie: Au fait, en C ++ 98, string(&v[0], v.size())devrait fonctionner aussi, mais seulement après assert(not v.empty());, puisque si le vecteur est vide, les deux v[0]et v.front()invoqueraient un comportement indéfini. Cela, mis à part la simplicité syntaxique de ne pas avoir à utiliser l'opérateur address-of, est le véritable avantage de la data()fonction de C ++ 11 , qui fonctionne même sur un vecteur vide.
Adam
Très vrai. Malheureusement, mon projet est bloqué sur Visual Studio 2008 dans un avenir prévisible. Juste à propos de la vérification de la longueur du vecteur en premier.
Jamie
Si le vecteur ne contient pas de '\ 0', cela std::string(v.data())peut entraîner une chaîne plus longue. Alors n'utilisez pas de cette façon.
heLomaN
@heLomaN: Quel est le problème avec std::string(v.data(), v.size()), qui a été explicitement mentionné dans la réponse pour cette raison exacte?
Sz.
12
std::string s(v.begin(), v.end());

Où v est à peu près tout itérable. (Plus précisément, begin () et end () doivent renvoyer des InputIterators.)

Martin Stone
la source
3

Juste pour être complet, une autre méthode est std::string(&v[0])(même si vous devez vous assurer que votre chaîne se termine par un caractère nul et qu'elle std::string(v.data())est généralement préférable.

La différence est que vous pouvez utiliser l'ancienne technique pour passer le vecteur aux fonctions qui souhaitent modifier le tampon, ce que vous ne pouvez pas faire avec .data ().

Émeute
la source
Pourquoi ne pouvez-vous pas utiliser data()pour modifier le tampon? Il me semble que si vous appelez data()un vecteur non-const, il retournera a T *(et si votre vecteur est const, 'v [0] `renverra de T const &toute façon).
Adam
@ AdamH.Peterson, cela semble être un oubli dans la norme. Les données de Std :: vector ont à la fois des fonctions const et non-const, alors que dans la norme actuelle, std :: string n'a qu'une fonction const: en.cppreference.com/w/cpp/string/basic_string/data Notez que C ++ 17 ajoute une version non-const, donc cela peut ne pas être le cas indéfiniment - cependant, la norme actuelle stipule que "La modification du tableau de caractères accessible via les données a un comportement indéfini."
Riot
Ce serait vrai s'il vs'agissait d'une chaîne, mais le type cible est une chaîne et vest un vecteur. (Mais il est agréable de voir que C ++ 17 donnera la parité des chaînes avec le vecteur.)
Adam
@ AdamH.Peterson vous avez raison, bien sûr. La question a reçu une réponse il y a quelque temps, j'avais supposé que toute la question concernait exclusivement les chaînes sans vérification.
Riot
2

J'aime la réponse de Stefan (11 septembre 2013) mais j'aimerais la rendre un peu plus forte:

Si le vecteur se termine par un terminateur nul, vous ne devez pas utiliser (v.begin (), v.end ()): vous devez utiliser v.data () (ou & v [0] pour ceux antérieurs à C ++ 17) .

Si v n'a pas de terminateur nul, vous devez utiliser (v.begin (), v.end ()).

Si vous utilisez begin () et end () et que le vecteur a un zéro de fin, vous vous retrouverez avec une chaîne "abc \ 0" par exemple, qui est de longueur 4, mais ne devrait vraiment être que "abc".

Henri Raath
la source
1
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());
TechCat
la source
Pourriez-vous ajouter quelques explications ainsi que le code?
Paul Floyd
1
Le modèle de bibliothèque de chaînes C ++ 11 se présente comme suit default (1) string (); copy (2) string (const string & str); substring (3) string (const string & str, size_t pos, size_t len ​​= npos); from c-string (4) string (const char * s); from buffer (5) string (const char * s, size_t n); fill (6) string (size_t n, char c); range (7) template <class InputIterator> string (InputIterator en premier, InputIterator en dernier); liste d'initialisation (8) chaîne (initializer_list <char> il); move (9) string (string && str) noexcept; nous suivons le 7ème modèle.
TechCat
Salut @TechCat! Veuillez lire la rédaction d'une bonne réponse avant de répondre à votre prochaine question. Profitez de votre séjour à SO!
Diggy.
Pourriez-vous modifier votre réponse avec la description s'il vous plaît?
Paul Floyd