2010-12-29 9 views
13

Qual è la differenza fondamentale, se esiste, tra un C++ std :: vector e std :: basic_string?Vector vs stringa

+1

Controllare i documenti, hanno interfacce diverse. Se hai specificato il problema che stai risolvendo, le risposte potrebbero essere anche più specifiche. –

+1

@Gene: hanno interfacce diverse, ma entrambe implementano tutto il necessario per essere un contenitore di sequenza STL. –

+0

@Gene: Non sto risolvendo alcun problema particolare, sono solo curioso di sapere perché dovrei scegliere l'uno o l'altro per vari scopi: non sto contando l'esistenza di alcuni metodi simili a stringhe come fondamentali. Neanche io considero le prestazioni come fondamentali. Comunque la validità degli iteratori è sicuramente confermata da diverse risposte. E ho il vago sospetto che il tipo di dati per una stringa debba avere un valore "Zero come" per mettere il metodo di fine data() (ottenuto da un thingy tratti). – Yttrill

risposta

0

Un vettore è una struttura di dati che simula una matrice. Nel profondo è in realtà una matrice (dinamica).

La classe basic_string rappresenta una sequenza di caratteri. Contiene tutte le normali operazioni di una sequenza e, inoltre, contiene operazioni di stringa standard come la ricerca e la concatenazione.

È possibile utilizzare il vettore per mantenere qualsiasi tipo di dati desiderato std::vector<int> or <float> or even std::vector< std::vector<T> > ma uno basic_string può essere utilizzato solo per rappresentare "testo".

+0

Sono sicuro che potrei trovare un modo per fare una 'basic_string' piena di doppi o qualcosa di altrettanto malvagio e che in effetti" funziona ". –

+0

Bene, molte implementazioni implementano 'basic_string' in termini di qualcosa come' vector'. E qualsiasi tipo per cui è definita una classe 'char_traits' funzionerà con' std :: basic_string', anche se hai creato un 'char_traits ' (come scritto nel commento di @ Noah) –

+0

@Billy - non vero. Alcune delle stesse tecniche potrebbero essere utilizzate in entrambi, ma non ho mai visto un 'basic_string' implementato in termini di' vector'. In effetti, un'implementazione molto comune, distribuita con MSVC++, è MOLTO diversa in quanto utilizzano l'ottimizzazione della stringa piccola (qualsiasi cosa abbastanza piccola da adattarsi a un puntatore è semplicemente bloccata nel puntatore al buffer anziché allocarla). –

0

La stringa di base fornisce molte opzioni di confronto specifiche per le stringhe. Hai ragione nel senso che l'interfaccia di gestione della memoria sottostante è molto simile, ma la stringa contiene molti membri aggiuntivi, come c_str(), che non avrebbe senso per un vettore.

+0

Non penso che esista un vettore che utilizza l'ottimizzazione delle stringhe di piccole dimensioni. Non sono uscito a cercarne uno, ma sono abbastanza sicuro che non è là fuori. Non sarebbe così utile. La verità è che le due cose sono semplicemente differenti. Hanno scopi diversi e spesso vengono implementati MOLTO diversamente, sebbene un approccio ingenuo possa essere simile in entrambi. –

+0

@ Noah: ecco perché ho detto "interfaccia". – Puppy

+0

Quali confronti sono specifici per le stringhe? Dato che il tipo di dati dell'elemento è variabile in entrambi i casi, le cose come il confronto lessicografico hanno tanto senso per i vettori quanto le stringhe. Naturalmente un confronto senza distinzione tra maiuscole e minuscole sarebbe una stringa specifica, ma la stringa non sarebbe polimorfica. – Yttrill

5

La differenza chiave è che std::vector dovrebbe mantenere i propri dati in memoria continua, quando std::basic_string non è in grado di. Di conseguenza:

std::vector<char> v('a', 3); 
char* x = &v[0]; // valid 

std::basic_string<char> s("aaa"); 
char* x2 = &s[0];  // doesn't point to continuous buffer 
//For example, the behavior of 
std::cout << *(x2+1); 
//is undefined. 
const char* x3 = s.c_str(); // valid 

On practice this difference is not so important.

+0

Err ... quell'esempio di codice è perfettamente valido.Ora se hai modificato 'x2' usando l'aritmetica del puntatore è possibile che non sia valido (dipende dal tuo compilatore), ma non sono a conoscenza di nessun compilatore che lo faccia. –

+0

Non sono a conoscenza di questo compilatore, ma non dovresti contare su quel 'x2' punta al buffer continuo, perché lo standard C++ non fornisce alcuna garanzia. –

+2

Nessuno di questi è effettivamente valido. Nessuno dei due oggetti ha alcuna dimensione e quindi il primo elemento è in realtà uno dopo la fine e non è possibile dereferenziare quell'elemento. Solo quello c_str() è ben definito. –

11

basic_string dà compilatore e le implementazioni della libreria standard, qualche libertà oltre vettore:

  1. L ' "ottimizzazione piccola stringa" è valida sulle corde, che permette implementazioni per memorizzare la stringa effettiva, piuttosto che un puntatore alla stringa, nell'oggetto stringa quando la stringa è breve. Qualcosa sulla falsariga di:

    class string 
    { 
        size_t length; 
        union 
        { 
         char * usedWhenStringIsLong; 
         char usedWhenStringIsShort[sizeof(char*)]; 
        }; 
    }; 
    
  2. In C++ 03, la matrice sottostante non deve essere contiguo. L'implementazione di basic_string in termini di qualcosa come una "corda" sarebbe possibile secondo lo standard corrente. (Anche se nessuno lo fa perché ciò renderebbe i membri std::basic_string::c_str() e std::basic_string::data() troppo costosi da implementare.)
    C++ 11 ora vieta questo comportamento.

  3. In C++ 03, basic_string permette l'/ fornitore libreria compilatore di utilizzare copy-on-write per i dati (che può risparmiare sulle copie), che non è consentito per std::vector. In pratica, questo era molto più comune, ma al giorno d'oggi è meno comune a causa dell'impatto che ha sul multithreading. In ogni caso, il tuo codice non può fare affidamento sul fatto che lo std::basic_string sia implementato o meno usando COW.
    Ora C++ 11 vieta nuovamente questo comportamento.

ci sono un paio di metodi di supporto appiccicato al basic_string pure, ma la maggior parte sono semplici e, naturalmente, potrebbe essere facilmente implementato in cima vector.

+0

Non mi piace pensare (1) come motivo per scegliere o utilizzare std :: string è un effetto indesiderato sul lato del testo standard che è stato rafforzato nel nuovo standard. (2) era una buona ragione per usare std :: string perché rendeva le stringhe di ritorno dai metodi molto efficienti (praticamente senza alcun costo), purtroppo questo viene rimosso a causa dei requisiti per il parallelismo (sebbene dalla lettura del documento che lo consiglia, sembra corda prenderà il mantello di COW alla fine (dovremo aspettare e vedere se funziona) –

+0

@Martin: Questo è vero. La semantica di spostamento OTOH elimina molti dei casi in cui le implementazioni di COW hanno accelerato le cose :) –

15
  • basic_string non chiama costruttori e distruttori dei suoi elementi. il vettore sì.

  • swapping basic_string invalida gli iteratori (consentendo l'ottimizzazione di stringhe di piccole dimensioni), lo scambio di vettori non lo fa.

  • La memoria di base_string non può essere allocata continuamente in C++ 03. il vettore è sempre continuo. Questa differenza viene rimosso in C++ 0x [string.require]:

    Gli oggetti char-simili in un oggetto basic_string sono memorizzati in modo contiguo

  • basic_string ha interfaccia per operazioni di stringa. il vettore no.

  • basic_string può utilizzare la copia sulla strategia di scrittura (in pre C++ 11). il vettore non può.

citazioni rilevanti per i non credenti:

[basic.string]:

Il modello di classe basic_string è conforme ai requisiti per un contenitore di sequenza (23.2.3), per un Reversible Container (23.2), e per un contenitore di Allocator-aware (Tabella 99), ad eccezione del fatto che basic_string non costruisce o distrugge i suoi elementi utilizzando allocator_traits :: construct e allocator_- tratti: destroy e that swap() per basic_string invalida gli iteratori. Gli iteratori supportati da di basic_string sono iteratori ad accesso casuale (24.2.7).

+0

@Billy: leggi lo standard prima del downvoting, ho aggiunto la citazione. – ybungalobill

+0

Per quanto posso dire, quella citazione non proviene da 'lo standard' ma dalla bozza C++ 0x. Va bene e vale la pena menzionarlo, ma è necessario qualificarlo con "In C++ 0x ...". – GManNickG

+0

@GMan: Hmm, sembra che tu abbia ragione. Ma solo la formulazione è diversa, il C++ 98 dice ancora che assegna e rilascia gli elementi solo. Questo cambiamento è solo un chiarimento. – ybungalobill

0

Una differenza tra std::string e std::vector è che i programmi possono costruire una stringa da una stringa con terminazione null, mentre con vettori non possono.

Questo spesso rende le stringhe più facili da utilizzare.

0

TLDR: string s sono ottimizzati per contenere solo primitivi caratteri, vector s possono contenere primitive o oggetti

La differenza preminente tra vector e string è che vector possono contenere correttamente oggetti, string funziona solo su primitive. Così vector fornisce questi metodi che sarebbero inutili per un string lavorare con primitive:

  1. vector::emplace
  2. vector::emplace_back
  3. vector::~vector

Anche estendentesi string non gli permetterà di gestire correttamente oggetti, perché manca un distruttore.Questo non deve essere visto come uno svantaggio, che consente di ottimizzare notevole su vector in quel string può:

  1. fare short string optimization, potenzialmente evitando allocazione heap, con little-no increased storage overhead
  2. Usa char_traits, uno dei template string s' argomenti, per definire come operazioni devono essere implementati su primitive contenute (di cui solo char, wchar_t, char16_t e char32_t sono implementate: http://en.cppreference.com/w/cpp/string/char_traits)

Particolarmente rilevanti sono char_traits::copy, char_traits::move e char_traits::assign che implicano ovviamente che l'assegnazione diretta, piuttosto che la costruzione o la distruzione, verrà utilizzata nuovamente, preferibile per le primitive. Tutto ciò specializzazione presenta gli inconvenienti aggiuntivi per string che:

  1. Solo char, saranno utilizzati wchar_t, char16_t o char32_t tipi primitivi. Ovviamente, le primitive di dimensioni fino a 32-bit, potrebbero utilizzare il loro equivalente di dimensioni char_type: https://stackoverflow.com/a/35555016/2642059, ma per primitive come long long avrebbe bisogno di essere scritta una nuova specializzazione di char_traits, e l'idea di specializzarsi char_traits::eof e char_traits::not_eof invece di usare vector<long long> non sembra il miglior uso del tempo.
  2. A causa di ottimizzazione stringa breve, iteratori sono invalidate da tutte le operazioni che potrebbero invalidare un iteratore vector, ma string iteratori sono inoltre invalidato da string::swap e string::operator=

differenze supplementare nelle interfacce di vector e string:

  1. non v'è mutabile string::data: Why Doesn't std::string.data() provide a mutable char*?
  2. string fornisce la funzionalità per lavorare con parole non disponibili in vector: string::c_str, string::length, string::append, string::operator+=, string::compare, string::replace, string::substr, string::copy, string::find, string::rfind, string::find_first_of, string::find_first_not_of, string::flind_last_of, string::find_last_not_of, string::operator+, string::operator>>, string::operator<<, string::stoi, string::stol, string::stoll, string::stoul, string::stoull, string::stof, string::stod, string::stold, stirng::to_string, string::to_wstring
  3. Infine ovunque vector accetta argomenti di un'altra vector, string accetta un stringo un char*

Nota che questa risposta è scritta nei confronti C++ 11, in modo da string s sono tenuti ad essere allocato in modo contiguo.