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?

oompahloompah
fonte
4
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:

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

o que levaria a algo como:

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

Eu acho que você pode apenas fazer

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

onde MyVector é seu std :: vector.

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

Ștefan
fonte
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.)

Martin Stone
fonte
3

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

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

Henri Raath
fonte
1
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());
TechCat
fonte
Você poderia adicionar algumas explicações, bem como o código?
Paul Floyd
1
O modelo de biblioteca de strings do C ++ 11 segue o seguinte default (1) string (); cópia (2) string (const string & str); substring (3) string (const string & str, size_t pos, size_t len ​​= npos); da string c (4) string (const char * s); do buffer (5) string (const char * s, size_t n); preencher (6) string (size_t n, char c); range (7) template <class InputIterator> string (InputIterator primeiro, InputIterator por último); lista de inicializadores (8) string (initializer_list <char> il); move (9) string (string && str) noexcept; estamos seguindo o 7º modelo.
TechCat
Olá @TechCat! Leia sobre como escrever uma boa resposta antes de responder à sua próxima pergunta. Aproveite a sua estadia no SO!
Diggy.
Você poderia editar sua resposta com a descrição, por favor?
Paul Floyd