char * vs std :: string in c ++

Quando dovrei usare std::string e quando dovrei usare char* per gestire gli array di char in C ++?

Sembra che dovresti usare char* se le prestazioni (velocità) sono cruciali e sei disposto ad accettare alcune attività rischiose a causa della gestione della memoria.

Ci sono altri scenari da considerare?

È ansible passare std :: string per riferimento se sono grandi per evitare la copia o un puntatore all’istanza, quindi non vedo alcun vantaggio reale utilizzando i puntatori di carattere.

Io uso std :: string / wstring per più o meno tutto ciò che è vero testo. char * è utile per altri tipi di dati e si può essere sicuri che venga deallocato come dovrebbe. Altrimenti std :: vector è la strada da percorrere.

Ci sono probabilmente delle eccezioni a tutto questo.

Il mio punto di vista è:

  • Non usare mai char * se non si chiama il codice “C”.
  • Usa sempre std :: string: è più facile, è più amichevole, è ottimizzato, è standard, ti impedisce di avere bug, è stato controllato e dimostrato di funzionare.

Utilizzo delle stringhe raw

Sì, a volte puoi davvero farlo. Quando si utilizza const char *, gli array di caratteri allocati nello stack e i letterali stringa possono essere eseguiti in modo tale che non vi sia alcuna allocazione di memoria.

Scrivere un codice di questo tipo richiede spesso più pensiero e cura che usare la stringa o il vettore, ma con le tecniche appropriate può essere fatto. Con le tecniche appropriate il codice può essere sicuro, ma è sempre necessario assicurarsi che quando si copia in char [] si abbia qualche garanzia sulla lunghezza della stringa da copiare, oppure si controlli e gestiscano le stringhe di dimensioni eccessive con garbo. Non farlo è ciò che ha reso la famiglia di funzioni una reputazione poco sicura.

Come i modelli possono aiutare a scrivere char buffer sicuri

Per quanto riguarda la sicurezza dei buffer char [], i template possono essere d’aiuto, poiché possono creare un incapsulamento per gestire la dimensione del buffer per te. Modelli come questo sono implementati ad esempio da Microsoft per fornire sostituzioni sicure per strcpy. L’esempio qui è estratto dal mio codice, il codice reale ha molti più metodi, ma questo dovrebbe essere sufficiente per trasmettere l’idea di base:

 template  class BString { char _data[Size]; public: BString() { _data[0]=0; // note: last character will always stay zero // if not, overflow occurred // all constructors should contain last element initialization // so that it can be verified during destruction _data[Size-1]=0; } const BString &operator = (const char *src) { strncpy(_data,src,Size-1); return *this; } operator const char *() const {return _data;} }; //! overloads that make conversion of C code easier template  inline const BString & strcpy(BString &dst, const char *src) { return dst = src; } 

Si dovrebbe prendere in considerazione l’uso di char* nei seguenti casi:

  • Questo array verrà passato in parametro.
  • Sai in anticipo la dimensione massima del tuo array (lo sai o lo imponi).
  • Non eseguirai alcuna trasformazione su questo array.

In realtà, in C ++, char* sono spesso usati per una parola piccola fissa, come opzioni, nome file, ecc …

Un’occasione in cui DEVI usare char* e non std::string è quando hai bisogno di costanti di stringa statiche. Il motivo è che non si ha alcun controllo sui moduli di ordine che inizializzano le loro variabili statiche e un altro object globale da un modulo diverso può fare riferimento alla stringa prima che sia inizializzata. http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Static_and_Global_Variables

std::string pro:

  • gestisce la memoria per te (la stringa può crescere e l’implementazione alloca un buffer più grande)
  • Interfaccia di programmazione di livello superiore, funziona bene con il resto di STL.

std::string cons: – due istanze di stringa STL distinte non possono condividere lo stesso buffer sottostante. Quindi se passi di valore ottieni sempre una nuova copia. – c’è qualche penalità sulle prestazioni, ma direi che a meno che le tue richieste siano speciali è trascurabile.

Quando usare un c ++ std :: string:

  • le stringhe, in generale, sono più sicure di char *, Normalmente quando fai le cose con char * devi controllare le cose per assicurarti che le cose siano nel giusto, nella class di stringhe tutto ciò è fatto per te.
  • Di solito quando si usa char *, si dovrà liberare la memoria allocata, non è necessario farlo con la stringa poiché libererà il suo buffer interno quando viene distrutta.
  • Le stringhe funzionano bene con lo stringstream c ++, l’IO formattato è molto semplice.

Quando usare char *

  • L’uso di char * ti dà un maggiore controllo su ciò che sta accadendo “dietro” le scene, il che significa che puoi adattare le prestazioni se necessario.

Usa (const) char * come parametri se stai scrivendo una libreria. std :: le implementazioni di stringhe differiscono tra i diversi compilatori.

Se vuoi usare le librerie C, dovrai fare i conti con le stringhe C. Lo stesso vale se vuoi esporre la tua API a C.

Potete aspettarvi che la maggior parte delle operazioni su una stringa std :: (come ad esempio find ) siano il più ottimizzate ansible, quindi è probabile che funzionino almeno altrettanto bene come una controparte C pura.

Vale anche la pena notare che gli iteratori di std :: string spesso si associano ai puntatori nel char array sottostante. Quindi qualsiasi algoritmo che si elabora sopra iteratori è essenzialmente identico allo stesso algoritmo in cima a char * in termini di prestazioni.

Le cose a cui prestare attenzione sono ad esempio l’ operator[] – la maggior parte delle implementazioni STL non esegue il controllo dei limiti e dovrebbe tradurla nella stessa operazione sull’array di caratteri sottostante. AFAIK STLPort può facoltativamente eseguire il controllo dei limiti, a quel punto questo operatore sarebbe un po ‘più lento.

Quindi cosa ti serve guadagnare std :: string? Ti assolve dalla gestione manuale della memoria; ridimensionare l’array diventa più semplice e generalmente si deve pensare meno alla liberazione della memoria.

Se sei preoccupato per le prestazioni durante il ridimensionamento di una stringa, c’è una funzione di reserve che potresti trovare utile.

se stai usando la matrice di caratteri in un testo simile, ecc. usa std :: string più flessibile e più facile da usare. Se lo usi per qualcos’altro come la memorizzazione dei dati? usa matrici (preferisci i vettori)

Anche quando le prestazioni sono cruciali, è meglio utilizzare il vector : consente l’allocazione della memoria in anticipo (metodo reserve ()) e consente di evitare perdite di memoria. L’uso di vector :: operator [] porta a un overhead, ma puoi sempre estrarre l’indirizzo del buffer e indicizzarlo esattamente come se fosse un char *.

AFAIK internamente la maggior parte della copia dello strumento std :: string sulla scrittura, la semantica di conteggio di riferimento per evitare il sovraccarico, anche se le stringhe non vengono passate per riferimento.