Come costruire uno std :: string da un std :: vector <char>?


115

A parte (l'ovvio) costruire prima una stringa in stile C e poi usarla per creare uno std :: string, esiste un modo più veloce / alternativo / "migliore" per inizializzare una stringa da un vettore di caratteri?


4
È possibile farlo senza copiare? In altre parole, qualcosa che fa la stessa cosa std::vector<char> v2(std::move(v))ma con un std::stringoggetto nuovo.
tobi_s

Risposte:


197

Bene, il modo migliore è usare il seguente costruttore:

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

che porterebbe a qualcosa di simile:

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

41

Penso che tu possa semplicemente fare

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

dove MyVector è il tuo std :: vector.


1
Tranne che in VS2013 che afferma in fase di esecuzione di iteratori non validi, a meno che non venga impostato _ITERATOR_DEBUG_LEVEL=1(nel qual caso sembra funzionare bene).
Cameron

35

Con C ++ 11, puoi fare std::string(v.data())o, se il tuo vettore non contiene un '\0'alla fine std::string(v.data(), v.size()),.


Anche con C ++ 98, credo che tu possa fare std :: string (& v [0]). Questo, ovviamente, è se il vettore è terminato da null.
Jamie

1
@ Jamie: A proposito, in C ++ 98, string(&v[0], v.size())dovrebbe funzionare anche, ma solo dopo assert(not v.empty());, poiché se il vettore è vuoto, entrambi v[0]e v.front()invocerebbero un comportamento indefinito. Questo, a parte la semplicità sintattica di non dover usare l'operatore address-of, è il vero vantaggio della funzione di C ++ 11 data(), che funziona anche su un vettore vuoto.
Adam H. Peterson

Verissimo. Sfortunatamente, il mio progetto è bloccato su Visual Studio 2008 per il prossimo futuro. Giusto per controllare prima la lunghezza del vettore.
Jamie

Se il vettore non contiene un "\ 0", std::string(v.data())potrebbe portare una stringa più lunga. Quindi non usare in questo modo.
heLomaN

@heLomaN: Cosa c'è che non va std::string(v.data(), v.size()), che è stato esplicitamente menzionato nella risposta per questo motivo esatto?
Sz.

12
std::string s(v.begin(), v.end());

Dove v è praticamente qualsiasi cosa iterabile. (In particolare, begin () e end () devono restituire InputIterators.)


3

Solo per completezza, un altro modo è std::string(&v[0])(anche se è necessario assicurarsi che la stringa sia terminata da null e std::string(v.data())generalmente è da preferire.

La differenza è che puoi usare la prima tecnica per passare il vettore alle funzioni che vogliono modificare il buffer, cosa che non puoi fare con .data ().


Perché non puoi usare data()per modificare il buffer? Mi sembra che se chiami data()su un vettore non const, restituirà a T *(e se il tuo vettore è const, 'v [0] `restituirebbe T const &comunque a).
Adam H. Peterson

@ AdamH.Peterson sembra essere una svista nello standard. I dati di Std :: vector hanno funzioni sia const che non cost, mentre nello standard corrente, std :: string ha solo una funzione const: en.cppreference.com/w/cpp/string/basic_string/data Nota che C ++ 17 aggiunge una versione non const, quindi questo potrebbe non essere il caso indefinitamente - tuttavia, lo standard corrente afferma "La modifica della matrice di caratteri a cui si accede tramite i dati ha un comportamento indefinito".
Riot

Ciò sarebbe vero se vfosse una stringa, ma il tipo di destinazione è una stringa ed vè un vettore. (Ma è bello vedere che C ++ 17 darà la parità delle stringhe con il vettore.)
Adam H. Peterson

@ AdamH.Peterson hai ragione ovviamente. Alla domanda è stata data una risposta qualche tempo fa, avevo pensato che l'intera domanda riguardasse esclusivamente le stringhe senza controllare.
Riot

2

Mi piace la risposta di Stefan (11 settembre 13) ma vorrei renderla un po 'più forte:

Se il vettore termina con un terminatore nullo, non dovresti usare (v.begin (), v.end ()): dovresti usare v.data () (o & v [0] per quelli precedenti a C ++ 17) .

Se v non ha un terminatore nullo, dovresti usare (v.begin (), v.end ()).

Se usi begin () e end () e il vettore ha uno zero terminale, ti ritroverai con una stringa "abc \ 0", ad esempio, che è di lunghezza 4, ma dovrebbe essere solo "abc".


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

Potresti aggiungere alcune spiegazioni oltre al codice?
Paul Floyd

1
Il modello di libreria di stringhe C ++ 11 funziona come segue default (1) string (); copy (2) string (const string & str); sottostringa (3) stringa (const string & str, size_t pos, size_t len ​​= npos); da c-string (4) stringa (const char * s); dal buffer (5) stringa (const char * s, size_t n); fill (6) stringa (size_t n, char c); range (7) template <class InputIterator> stringa (InputIterator per primo, InputIterator per ultimo); lista inizializzatore (8) stringa (inizializzatore_elenco <char> il); move (9) string (string && str) noexcept; stiamo seguendo il 7 ° modello.
TechCat

Ciao @TechCat! Si prega di leggere su come scrivere una buona risposta prima di rispondere alla prossima domanda. Buon soggiorno a SO!
Diggy.

Potresti modificare la tua risposta con la descrizione per favore?
Paul Floyd
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.