¿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?
¿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:
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()),.
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.)
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 ().
¿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".
std::vector<char> v2(std::move(v))
pero con astd::string
como el nuevo objeto.Respuestas:
Bueno, la mejor manera es usar el siguiente constructor:
lo que conduciría a algo como:
fuente
Creo que puedes hacer
donde MyVector es su std :: vector.
fuente
_ITERATOR_DEBUG_LEVEL=1
(en cuyo caso parece funcionar bien).Con C ++ 11, puede hacer
std::string(v.data())
o, si su vector no contiene un'\0'
al finalstd::string(v.data(), v.size())
,.fuente
string(&v[0], v.size())
debería funcionar también, pero solo despuésassert(not v.empty());
, ya que si el vector está vacío, ambosv[0]
ev.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 ladata()
función de C ++ 11 , que funciona incluso en un vector vacío.std::string(v.data())
puede llevar una cadena más larga. Así que no lo use de esta manera.std::string(v.data(), v.size())
, que se mencionó explícitamente en la respuesta por esa razón exacta?Donde v es prácticamente cualquier cosa iterable. (Específicamente begin () y end () deben devolver InputIterators.)
fuente
Solo para completar, otra forma es
std::string(&v[0])
(aunque debe asegurarse de que su cadena tenga terminación nula ystd::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 ().
fuente
data()
para modificar el búfer? Me parece que si llamadata()
a un vector no constante, devolverá unT *
(y si su vector es constante, 'v [0] `devolverá un deT const &
todos modos).v
fuera una cadena, pero el tipo de destino es una cadena yv
es un vector. (Pero es bueno ver que C ++ 17 le dará a las cadenas paridad con el vector)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".
fuente
fuente