Perché ci sono così tante classi di stringhe di fronte a std :: string?


56

Mi sembra che molte più grandi librerie C ++ finiscano per creare il proprio tipo di stringa. Nel codice cliente si hanno o utilizzare quello dalla libreria ( QString, CString, fbstringecc, sono sicuro che chiunque può citarne alcuni), o mantenere la conversione tra il tipo standard e quello gli usi della biblioteca (che il più delle volte comporta almeno una copia).

Quindi, c'è una particolare disfunzione o qualcosa di sbagliato std::string(proprio come la auto_ptrsemantica era cattiva)? È cambiato in C ++ 11?


32
Si chiama "Non inventato qui sindrome".
Cat Plus Plus,

10
@CatPlusPlus QString e CString sono entrambi preceduti da std :: string.
Gort the Robot,

8
@Cat Plus Plus: questa sindrome non sembra influenzare la classe String Java.
Giorgio,

20
@Giorgio: i programmatori Java sono troppo impegnati a inventare soluzioni alternative per le carenze del linguaggio per preoccuparsi delle classi di stringhe (Android ha reinventato String, tra l'altro).
Cat Plus Plus,

9
@Giorgio: Probabilmente è perché il supporto sintattico codificato da Java per java.lang.String(mancanza di sovraccarico dell'operatore, ecc.) Renderebbe doloroso usare qualsiasi altra cosa.
Lumaca meccanica

Risposte:


57

La maggior parte di quelle più grandi librerie C ++ sono state avviate prima che std::stringfosse standardizzato. Altri includono funzionalità aggiuntive standardizzate in ritardo o ancora non standardizzate, come il supporto per UTF-8 e la conversione tra codifiche.

Se quelle librerie fossero implementate oggi, probabilmente sceglierebbero di scrivere funzioni e iteratori che operano su std::stringistanze.


5
Il supporto per UTF-8 è standardizzato da C ++ 98. In un modo così scomodo e parzialmente definito dall'implementazione che nessuno sembra essere in grado di usarlo
AProgrammer

9
@AProgrammer: charè garantito che sia abbastanza grande da contenere qualsiasi punto di codice UTF-8. AFAIK, questo è l'unico "supporto" fornito da C ++ 98.
Ben Voigt,

4
@AProgrammer: questo supporto è davvero abbastanza inutile.
DeadMG

4
@AProgrammer Quella locale è probabilmente interrotta poiché nonwchar_t è abbastanza grande per rappresentare tutti i punti di codice Unicode. Inoltre, c'è stata tutta questa discussione su UTF-16 considerata dannosa in cui è stata fatta l'argomentazione molto convincente che UTF-8 dovrebbe essere usato esclusivamente ...
Konrad Rudolph,

6
@KonradRudolph, non è il sistema locale ad essere rotto lì (la definizione di wchar_t è "abbastanza ampia per qualsiasi set di caratteri supportato"); i sistemi che hanno eseguito il commit a 16 bit che wchar_t si è impegnato contemporaneamente a non supportare Unicode. Bene, il colpevole è Unicode che per primo ha garantito che non avrebbe mai usato i punti di codice che richiedessero più di 16 bit, quindi i sistemi che si impegnano in un wchar_t a 16 bit, quindi la commutazione unicode per richiedere più di 16 bit.
Circa

39

String è il grande imbarazzo del C ++.

Per i primi 15 anni non fornisci affatto una classe di stringhe, costringendo ogni compilatore su ogni piattaforma e ogni utente a crearne una propria.

Quindi fai qualcosa di confuso sul fatto che debba essere un'API di manipolazione di stringhe complete o solo un contenitore di caratteri STL, con alcuni algoritmi che duplicano quelli su uno std :: Vector o sono diversi.

Laddove un'operazione stringa ovvia come sostituisca () o mid () comporta un tale disordine di iteratori che è necessario introdurre una nuova parola chiave "auto" per mantenere l'adattamento dell'istruzione su una singola pagina e indurre la maggior parte delle persone a rinunciare all'intera lingua .

E poi hai unicode 'support' e std :: wstring che è solo arghh .....

<rant off> grazie - Adesso mi sento molto meglio.


12
@DeadMG - sì ed è stato standardizzato nel 1998, 15 anni dopo l'invenzione e 6 anni dopo che anche MSFT lo utilizzava. Sì, gli iteratori sono un modo utile per fare in modo che un array e un elenco sembrino uguali, pensi che siano un modo ovvio per manipolare le stringhe?
Martin Beckett,

3
C with Classes è stato inventato nel 1983. Non C ++. Le uniche librerie Standard sono quelle determinate da Standard, che, stranamente, può accadere solo una volta che hai uno Standard, quindi la prima data possibile per qualsiasi libreria Standard è il 1998. E gli iteratori possono essere considerati esattamente uguali agli indici, ma fortemente tipizzati. Sono tutto per il fatto che gli iteratori fanno schifo rispetto alle gamme, ma non è proprio specifico std::string. La mancanza di una classe String nel 1983 non giustifica averne di più ora.
DeadMG

8
Pensavo che gli iostreams fossero il grande imbarazzo del C ++ ...
Doug T.

18
@DeadMG La gente usava qualcosa chiamato "C ++" per molti anni prima del 1998. Ho scritto il mio primo programma usando qualcosa chiamato "C ++" nel 1985. Se vuoi dire che questo non è "vero" C ++, va bene, ma prima di questo, stavamo scrivendo codice e dovevamo ottenere una classe di stringa da qualche parte. Una volta che avevamo queste basi di codice legacy, non potevamo esattamente buttarle fuori o riscriverle da zero quando abbiamo ottenuto uno standard. Ora quello che avrebbe dovuto succedere è che ci sarebbe dovuta essere una classe di stringhe fornita con cfront.
Gort il robot il

8
@DeadMG - Se nessuno avesse usato una lingua fino a quando non avesse ottenuto la certificazione ISO, nessuna lingua sarebbe mai stata usata poiché non sarebbe mai arrivata all'ISO. Non esiste uno standard ISO per l'assemblatore x86 ma sono felice di usare la piattaforma
Martin Beckett il

32

In realtà ... ci sono diversi problemi con std::string, e sì, in C ++ 11 migliora un po ', ma non anticipiamo noi stessi.

QStringe CStringfanno parte di vecchie librerie, quindi esistevano prima che il C ++ fosse standardizzato (proprio come lo SGI STL). Hanno quindi avuto per creare una classe.

fbstringaffrontare problematiche prestazionali molto specifiche. Lo standard prescrive un'interfaccia e la complessità algoritmica garantisce i minimi, tuttavia è una qualità di dettagli di implementazione se questo finisce per essere veloce o no. fbstringha ottimizzazioni specifiche (relative allo spazio di archiviazione o findad esempio più veloci ).

Altre preoccupazioni che non sono state evocate qui (en vrac):

  • in C ++ 03 non è obbligatorio che la memoria sia contigua, rendendo potenzialmente difficile l'interoperabilità con C. C ++ 11 risolve questo problema.
  • std::string sta codificando inconsapevolmente e non ha un codice speciale per UTF-8, è facile memorizzare una stringa UTF-8 e danneggiarla involontariamente
  • std::stringl'interfaccia è gonfia , molti metodi potrebbero essere stati implementati come funzioni libere e molti sono duplicati per conformarsi sia a un'interfaccia basata su indice sia a un'interfaccia basata su iteratore.

5
Riguardo al n. 1 - C ++ 03 21.3.6 / 1 garantisce che c_str()restituisce un puntatore alla memoria contigua, che prevede una certa interoperabilità C. Tuttavia, non è possibile modificare i dati puntati. Soluzioni alternative tipiche includono l'utilizzo di a vector<char>.
John Dibling,

@JohnDibling: Sì, e c'è un'altra limitazione: potrebbe incorrere in una copia nella memoria appena allocata (lo Standard non dice che non dovrebbe). Naturalmente C ++ 11 non impedisce nemmeno la copia, ma dal momento che puoi semplicemente farlo &s[0]non importa più :)
Matthieu M.

1
@MatthieuM .: Il puntatore ottenuto tramite &s[0]non può puntare a una stringa terminata con NUL (a meno che non c_str()sia stato chiamato dall'ultima modifica).
Ben Voigt,

2
@Matthieu: un altro buffer non è consentito. " c_str()Restituisce: un puntatore ptale che p + i == &operator[](i)per ciascuno iin [0,size()]".
Ben Voigt,

3
Ciò che vale anche la pena notare è che nessuno nella loro mente corretta usa più MFC, quindi è difficile sostenere che CString sia una classe di stringhe nel moderno C ++.
DeadMG

7

Oltre ai motivi pubblicati qui, ce n'è anche un altro: la compatibilità binaria . Gli autori delle librerie non hanno alcun controllo su quale std::stringimplementazione si sta utilizzando e se ha lo stesso layout di memoria della loro.

std::stringè un modello, quindi la sua implementazione è presa dalle intestazioni STL locali. Ora immagina di utilizzare localmente una versione STL ottimizzata per le prestazioni, pienamente compatibile con lo standard. Ad esempio, è possibile che si sia scelto di inserire un buffer statico in ciascuno std::stringdi essi per ridurre il numero di allocazioni dinamiche e errori nella cache. Di conseguenza, il layout e / o la dimensione della memoria dell'implementazione sono diversi da quelli della libreria.

Se solo il layout è diverso, alcune std::stringfunzioni dei membri richiamano istanze passate dalla libreria al client o viceversa potrebbero non riuscire, a seconda di quali membri sono stati spostati.

Se anche la dimensione è diversa, tutti i tipi di libreria che hanno std::stringmembri appariranno di dimensioni diverse quando vengono controllati nella libreria e nel codice client. Anche i membri di dati che seguono il std::stringmembro avranno gli offset spostati, e qualsiasi accesso diretto / accessorio in linea chiamato dal client restituirà spazzatura, nonostante "sembri OK" durante il debug della libreria stessa.

In conclusione: se la libreria e il codice client vengono compilati di nuovo in std::stringversioni diverse , si collegheranno perfettamente, ma potrebbe risultare in alcuni bug cattivi e difficili da capire. Se si modifica l' std::stringimplementazione, è necessario ricompilare tutte le librerie che espongono i membri da STL in modo che corrispondano al std::stringlayout del client . E poiché i programmatori vogliono che le loro librerie siano robuste, raramente le vedrai std::stringesposte ovunque.

Ad essere onesti, questo vale per tutti i tipi di STL. IIRC non hanno layout di memoria standardizzati.


2
Devi essere un programmatore * nix. La compatibilità binaria C ++ non è uguale su tutte le piattaforme, e in particolare su Windows le classi NO contenenti membri di dati sono portatili tra i compilatori.
Ben Voigt,

(Intendo ad eccezione dei tipi POD, e anche allora sono necessari requisiti di imballaggio espliciti)
Ben Voigt

1
Grazie per l'input, anche se non sto parlando di un compilatore diverso, sto parlando di STL diversi.
gwiazdorrr,

1
+1: ABI è una grande ragione per pubblicare la tua versione di una classe fornita dal compilatore. Solo per questo, vorrei che questa fosse la risposta accettata.
Thomas Eding,

6

Ci sono molte risposte alla domanda ma eccone alcune:

  1. Legacy. Molte librerie e classi di stringhe sono state scritte PRIMA dell'esistenza di std :: string.

  2. Per compatibilità con il codice in C. La libreria std :: string è C ++ dove come ci sono altre librerie di stringhe che funzionano con C e C ++.

  3. Per evitare allocazioni dinamiche. La libreria std :: string utilizza l'allocazione dinamica e potrebbe non essere adatta per sistemi integrati, codice di interrupt o in tempo reale o per funzionalità di basso livello.

  4. Modelli. La libreria std :: string si basa su modelli. Fino a poco tempo fa un certo numero di compilatori C ++ aveva scarse prestazioni o addirittura un supporto per il modello difettoso. Sfortunatamente, lavoro in un settore che utilizza molti strumenti personalizzati e una delle nostre catene di strumenti di uno dei principali attori del settore non supporta "ufficialmente" il 100% del C ++ (con roba buggy come template et al).

Probabilmente ci sono anche molte altre ragioni valide.


2
"Abbastanza recentemente" significa "È passato un decennio da quando anche Visual Studio ha avuto un supporto abbastanza ragionevole per loro"?
DeadMG

@DeadMG - Visual Studio non è l'unico compilatore non conforme al mondo. Lavoro nei videogiochi e spesso stiamo lavorando a compilatori personalizzati per piattaforme hardware inedite (succede ogni pochi anni nei cicli della console o quando appare nuovo hardware). "Abbastanza recentemente" significa oggi - Al momento alcuni compilatori non supportano bene i template. Non posso essere specifico senza violare NDA, ma attualmente sto lavorando su una piattaforma con toolchain personalizzati in cui il supporto C ++, in particolare la conformità dei modelli, è considerato "sperimentale".
Adisak,

4

Si tratta principalmente di Unicode. Il supporto standard per Unicode è nella migliore delle ipotesi e ognuno ha le proprie esigenze Unicode. Ad esempio, ICU supporta tutte le funzionalità Unicode che potresti desiderare, dietro l'interfaccia più disgustosa generata automaticamente da Java che potresti immaginare, e se sei su Unix bloccato con UTF-16 potrebbe non essere la tua idea di un buon momento.

Inoltre, molte persone hanno bisogno di livelli diversi di supporto Unicode, non tutti hanno bisogno delle complesse API del layout del testo e cose del genere. Quindi è facile capire perché esistono numerose classi di stringhe: quella standard è piuttosto schifosa e tutti hanno esigenze diverse da quelle nuove, senza che nessuno riesca a creare una singola classe in grado di eseguire un sacco di supporto Unicode multipiattaforma con un'interfaccia piacevole.

Secondo me, questo è principalmente colpa del Comitato C ++ per non aver fornito correttamente supporto per Unicode nel 1998 o 2003, forse era comprensibile, ma non in C ++ 11. Eventualmente in C ++ 17 faranno meglio.


Ciao, C ++ 20 qui, indovina cosa è successo al supporto Unicode?
Passante entro il

-4

È perché ogni programmatore ha qualcosa da dimostrare e sente il bisogno di creare la propria classe di stringhe fantastica e più veloce per la sua unica, fantastica funzione. Di solito è un po 'superfluo e porta a tutti i tipi di conversioni di stringa extra nella mia esperienza.


7
Se questo fosse vero, mi aspetto di vedere un numero simile di implementazioni di stringhe in linguaggi come Java, dove una buona implementazione è sempre stata disponibile.
Bill K,

@BillK la stringa Java è definitiva, quindi devi aggiungere nuove funzionalità altrove.

E il mio punto è, anche se definitivo, in 20 anni che non ho mai visto nessuno scrivere un'impelementazione personalizzata delle stringhe (beh, ho cercato di migliorare le prestazioni di concatenazione delle stringhe, ma risulta che java è MOLTO più intelligente di string + string di te ' d immaginare)
Bill K,

2
@Bill: potrebbe avere a che fare con una cultura diversa. Il C ++ attira coloro che vogliono capire i dettagli di basso livello. Java attira coloro che vogliono semplicemente portare a termine il lavoro usando i mattoni di qualcun altro. (Nota che questa non è un'affermazione su un individuo specifico che sceglie di usare una delle due lingue, ma sugli obiettivi e sulla cultura dei rispettivi linguaggi)
Ben Voigt,
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.