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?


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());

41

Je pense que tu peux juste faire

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

où MyVector est votre std :: vector.


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()),.


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.)


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


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".


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

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.