Como construir um std :: string a partir de um std :: vector <char>?
115
Sem (o óbvio) construir primeiro uma string de estilo C e então usá-la para criar uma string std :: string, existe uma maneira mais rápida / alternativa / "melhor" de inicializar uma string a partir de um vetor de caracteres?
Isso pode ser feito sem copiar? Em outras palavras, algo que faz a mesma coisa, std::vector<char> v2(std::move(v))mas com a std::stringcomo o novo objeto.
tobi_s
Respostas:
197
Bem, a melhor maneira é usar o seguinte construtor:
Exceto no VS2013 que afirma em tempo de execução sobre iteradores inválidos, a menos que você defina _ITERATOR_DEBUG_LEVEL=1(nesse caso, parece funcionar bem).
Cameron
35
Com C ++ 11, você pode fazer std::string(v.data())ou, se o seu vetor não contiver um '\0'no final std::string(v.data(), v.size()),.
Mesmo com C ++ 98, acredito que você pode fazer std :: string (& v [0]). Isso, é claro, se o vetor tiver terminação nula.
Jamie de
1
@Jamie: Aliás, em C ++ 98, string(&v[0], v.size())deve funcionar também, mas só depois assert(not v.empty());, já que se o vetor estiver vazio, ambos v[0]e v.front()invocariam um comportamento indefinido. Esse, além da simplicidade sintática de não ter que usar o operador address-of, é o real benefício da data()função do C ++ 11 , que funciona mesmo em um vetor vazio.
Adam H. Peterson,
Muito verdadeiro. Infelizmente, meu projeto está preso no Visual Studio 2008 no futuro próximo. Certo sobre verificar o comprimento do vetor primeiro.
Jamie
Se o vetor não contém um '\ 0', std::string(v.data())pode levar uma string mais longa. Portanto, não use desta forma.
heLomaN
@heLomaN: Qual é o problema std::string(v.data(), v.size()), o que foi explicitamente mencionado na resposta exatamente por esse motivo?
Sz.
12
std::string s(v.begin(), v.end());
Onde v é praticamente qualquer coisa iterável. (Especificamente, begin () e end () devem retornar InputIterators.)
Apenas para completar, outra maneira é std::string(&v[0])(embora você precise garantir que sua string tenha terminação nula estd::string(v.data()) seja geralmente a preferida.
A diferença é que você pode usar a técnica anterior para passar o vetor para funções que desejam modificar o buffer, o que você não pode fazer com .data ().
Por que você não pode usar data()para modificar o buffer? Parece-me que se você chamar data()um vetor não const, ele retornará a T *(e se o seu vetor for const, 'v [0] `retornará a de T const &qualquer maneira).
Adam H. Peterson,
@ AdamH.Peterson parece ser um descuido no padrão. Os dados de Std :: vector têm funções const e não const, enquanto no padrão atual, std :: string tem apenas uma função const: en.cppreference.com/w/cpp/string/basic_string/data Observe que C ++ 17 adiciona uma versão não const, portanto, pode não ser o caso indefinidamente - no entanto, o padrão atual afirma "Modificar a matriz de caracteres acessada por meio de dados tem comportamento indefinido."
Riot de
Isso seria verdade se vfosse uma string, mas o tipo de destino é uma string e vé um vetor. (Mas é bom ver que C ++ 17 dará paridade de strings com vetor.)
Adam H. Peterson
@ AdamH.Peterson você está certo, é claro. A pergunta foi respondida um tempo atrás, eu assumi que toda a questão era sobre strings exclusivamente sem verificação.
Motim de
2
Gosto da resposta de Stefan (11 de setembro de 13), mas gostaria de torná-la um pouco mais forte:
Se o vetor terminar com um terminador nulo, você não deve usar (v.begin (), v.end ()): você deve usar v.data () (ou & v [0] para aqueles anteriores a C ++ 17) .
Se v não tiver um terminador nulo, você deve usar (v.begin (), v.end ()).
Se você usar begin () e end () e o vetor tiver um zero final, você terminará com uma string "abc \ 0" por exemplo, que tem comprimento 4, mas deveria ser apenas "abc".
std::vector<char> v2(std::move(v))
mas com astd::string
como o novo objeto.Respostas:
Bem, a melhor maneira é usar o seguinte construtor:
o que levaria a algo como:
fonte
Eu acho que você pode apenas fazer
onde MyVector é seu std :: vector.
fonte
_ITERATOR_DEBUG_LEVEL=1
(nesse caso, parece funcionar bem).Com C ++ 11, você pode fazer
std::string(v.data())
ou, se o seu vetor não contiver um'\0'
no finalstd::string(v.data(), v.size())
,.fonte
string(&v[0], v.size())
deve funcionar também, mas só depoisassert(not v.empty());
, já que se o vetor estiver vazio, ambosv[0]
ev.front()
invocariam um comportamento indefinido. Esse, além da simplicidade sintática de não ter que usar o operador address-of, é o real benefício dadata()
função do C ++ 11 , que funciona mesmo em um vetor vazio.std::string(v.data())
pode levar uma string mais longa. Portanto, não use desta forma.std::string(v.data(), v.size())
, o que foi explicitamente mencionado na resposta exatamente por esse motivo?Onde v é praticamente qualquer coisa iterável. (Especificamente, begin () e end () devem retornar InputIterators.)
fonte
Apenas para completar, outra maneira é
std::string(&v[0])
(embora você precise garantir que sua string tenha terminação nula estd::string(v.data())
seja geralmente a preferida.A diferença é que você pode usar a técnica anterior para passar o vetor para funções que desejam modificar o buffer, o que você não pode fazer com .data ().
fonte
data()
para modificar o buffer? Parece-me que se você chamardata()
um vetor não const, ele retornará aT *
(e se o seu vetor for const, 'v [0] `retornará a deT const &
qualquer maneira).v
fosse uma string, mas o tipo de destino é uma string ev
é um vetor. (Mas é bom ver que C ++ 17 dará paridade de strings com vetor.)Gosto da resposta de Stefan (11 de setembro de 13), mas gostaria de torná-la um pouco mais forte:
Se o vetor terminar com um terminador nulo, você não deve usar (v.begin (), v.end ()): você deve usar v.data () (ou & v [0] para aqueles anteriores a C ++ 17) .
Se v não tiver um terminador nulo, você deve usar (v.begin (), v.end ()).
Se você usar begin () e end () e o vetor tiver um zero final, você terminará com uma string "abc \ 0" por exemplo, que tem comprimento 4, mas deveria ser apenas "abc".
fonte
fonte