¿Cómo construir un std :: string a partir de un std :: vector <char>?

115

Aparte de (lo obvio) construir una cadena de estilo C primero y luego usarla para crear una std :: string, ¿hay una forma más rápida / alternativa / "mejor" de inicializar una cadena a partir de un vector de caracteres?

oompahloompah
fuente
4
¿Se puede hacer esto sin copiar? En otras palabras, algo que hace lo mismo que std::vector<char> v2(std::move(v))pero con a std::stringcomo el nuevo objeto.
tobi_s

Respuestas:

197

Bueno, la mejor manera es usar el siguiente constructor:

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

lo que conduciría a algo como:

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

Creo que puedes hacer

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

donde MyVector es su std :: vector.

LiMuBei
fuente
1
Excepto en VS2013 que afirma en tiempo de ejecución sobre iteradores no válidos, a menos que lo establezca _ITERATOR_DEBUG_LEVEL=1(en cuyo caso parece funcionar bien).
Cameron
35

Con C ++ 11, puede hacer std::string(v.data())o, si su vector no contiene un '\0'al final std::string(v.data(), v.size()),.

Ștefan
fuente
Incluso con C ++ 98, creo que puedes hacer std :: string (& v [0]). Esto, por supuesto, es si el vector termina en nulo.
Jamie
1
@Jamie: Por cierto, en C ++ 98, string(&v[0], v.size())debería funcionar también, pero solo después assert(not v.empty());, ya que si el vector está vacío, ambos v[0]e v.front()invocarían un comportamiento indefinido. Eso, aparte de la simplicidad sintáctica de no tener que usar el operador address-of, es el beneficio real de la data()función de C ++ 11 , que funciona incluso en un vector vacío.
Adam H. Peterson
Muy cierto. Desafortunadamente, mi proyecto está bloqueado en Visual Studio 2008 en el futuro previsible. Justo antes de verificar la longitud del vector.
Jamie
Si el vector no contiene un '\ 0', std::string(v.data())puede llevar una cadena más larga. Así que no lo use de esta manera.
heLomaN
@heLomaN: ¿Qué tiene de malo std::string(v.data(), v.size()), que se mencionó explícitamente en la respuesta por esa razón exacta?
Sz.
12
std::string s(v.begin(), v.end());

Donde v es prácticamente cualquier cosa iterable. (Específicamente begin () y end () deben devolver InputIterators.)

Martin Stone
fuente
3

Solo para completar, otra forma es std::string(&v[0])(aunque debe asegurarse de que su cadena tenga terminación nula y std::string(v.data())generalmente sea la preferida.

La diferencia es que puede usar la técnica anterior para pasar el vector a funciones que quieran modificar el búfer, lo que no puede hacer con .data ().

Alboroto
fuente
¿Por qué no se puede utilizar data()para modificar el búfer? Me parece que si llama data()a un vector no constante, devolverá un T *(y si su vector es constante, 'v [0] `devolverá un de T const &todos modos).
Adam H. Peterson
@ AdamH.Peterson parece ser un descuido en el estándar. Los datos de std :: vector tienen funciones const y no const, mientras que en el estándar actual, std :: string solo tiene una función const: en.cppreference.com/w/cpp/string/basic_string/data Tenga en cuenta que C ++ 17 agrega una versión no constante, por lo que puede que este no sea el caso indefinidamente; sin embargo, el estándar actual dice "La modificación de la matriz de caracteres a la que se accede a través de los datos tiene un comportamiento indefinido".
Riot
Eso sería cierto si vfuera una cadena, pero el tipo de destino es una cadena y ves un vector. (Pero es bueno ver que C ++ 17 le dará a las cadenas paridad con el vector)
Adam H. Peterson
@ AdamH.Peterson tienes razón, por supuesto. La pregunta fue respondida hace un tiempo, asumí que toda la pregunta se refería exclusivamente a cadenas sin verificar.
Riot
2

Me gusta la respuesta de Stefan (11 de septiembre de 2013) pero me gustaría hacerla un poco más fuerte:

Si el vector termina con un terminador nulo, no debe usar (v.begin (), v.end ()): debe usar v.data () (o & v [0] para aquellos anteriores a C ++ 17) .

Si v no tiene un terminador nulo, debe usar (v.begin (), v.end ()).

Si usa begin () y end () y el vector tiene un cero final, terminará con una cadena "abc \ 0", por ejemplo, que es de longitud 4, pero en realidad debería ser solo "abc".

Henri Raath
fuente
1
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());
TechCat
fuente
¿Podría agregar algunas explicaciones además del código?
Paul Floyd
1
La plantilla de biblioteca de cadenas de C ++ 11 es la siguiente: default (1) string (); copy (2) string (const string & str); substring (3) string (const string & str, size_t pos, size_t len ​​= npos); de c-string (4) string (const char * s); from buffer (5) string (const char * s, size_t n); fill (6) cadena (size_t n, char c); range (7) template <class InputIterator> cadena (InputIterator primero, InputIterator al final); initializer list (8) string (initializer_list <char> il); mover (9) cadena (cadena && str) noexcepto; estamos siguiendo la 7ma plantilla.
TechCat
Hola @TechCat! Lea sobre cómo escribir una buena respuesta antes de responder su próxima pregunta. ¡Disfrute de su estancia en SO!
Diggy.
¿Podrías editar tu respuesta con la descripción por favor?
Paul Floyd