2010-01-31 11 views
12

Dalla documentazione del StringPiece class in Chromium's source code:Ci sono motivi per cui l'idioma StringPiece/StringRef non è più popolare?

// A string-like object that points to a sized piece of memory. 
// 
// Functions or methods may use const StringPiece& parameters to accept either 
// a "const char*" or a "string" value that will be implicitly converted to 
// a StringPiece. 
// 
// Systematic usage of StringPiece is encouraged as it will reduce unnecessary 
// conversions from "const char*" to "string" and back again. 

Esempio di utilizzo:

void foo(StringPiece const & str) // Pass by ref. is probably not needed 
{ 
    // str has same interface of const std::string 
} 

int main() 
{ 
    string bar("bar"); 
    foo(bar); // OK, no mem. alloc. 

    // No mem. alloc. either, would be if arg. of "foo" was std::string 
    foo("baz"); 
} 

Questo mi sembra un'ottimizzazione così importante ed evidente che non riesco a capire il motivo per cui non è più diffuso, e perché una classe simile a StringPiece non è già nello standard.

Ci sono motivi per cui non dovrei sostituire l'uso dei parametri string e char* nel mio codice con questa classe? C'è qualcosa di simile già nelle librerie standard C++?

UPDATE. Ho appreso che la fonte di LLVM utilizza un concetto simile: la classe StringRef.

+0

Mi piace questa idea teorica. Mi chiedo quanto possa essere confuso nella pratica senza "allenamento". – jmucchiello

+1

Vecchio post, ma per i futuri lettori dovrebbe notare che è stato proposto: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html –

risposta

-7

Perché preoccuparsi? Con copia elision e/o passare per riferimento, di solito si possono evitare anche allocazioni di memoria per std::string.

La situazione delle stringhe in C++ è abbastanza confusa, senza aggiungere altre classi di stringhe.

Se il linguaggio doveva essere riprogettato da zero o se la compatibilità con le versioni precedenti non era un problema, questo è uno dei molti possibili miglioramenti che potrebbero essere apportati alla gestione delle stringhe in C++. Ma ora che siamo bloccati sia con lo char* sia con lo std::string, l'aggiunta di una classe in stile stringa nel mix causerebbe molta confusione, con un beneficio limitato.

A parte questo, non è lo stesso effetto ottenuto più idiomaticamente con un paio di iteratori? Se voglio passare una sequenza di caratteri, sia che appartengano a una stringa o a char*, perché non dovrei semplicemente usare un paio di iteratori per delimitarli?

+3

Ma se si utilizza la route "due iteratori", è necessario inventare una classe analoga a StringPiece che offre un'interfaccia simile a una stringa. E la prima riga delle tue funzioni sarebbe sempre qualcosa come "StringRange str (str_beg, str_end);".Accettato comunque per aver fornito la miglior valutazione finora. – Manuel

+0

Vero sulla comoda interfaccia simile a una stringa, ma ancora una volta, ricorda che gli iteratori sono già idiomatici in C++. Non vedo perché le tue funzioni avrebbero bisogno di creare un stringrange dagli iteratori. Invece, l'intera interfaccia di manipolazione delle stringhe avrebbe dovuto essere fornita come funzioni gratuite sugli iteratori per cominciare. La libreria StringAlgo di Boost risolve gran parte di ciò. – jalf

+0

Non penso che ti piacerebbe davvero quello che stai suggerendo. Immagina qualcosa di semplice come 'strA + strB + strC' in termini di iteratori. – Manuel

0

Lo standard sta tentando di spostarsi da const char * in favore di stringa del tutto, quindi aggiungere ulteriori opzioni per la conversione è inutile.

Si noti inoltre che un programma ben formato dovrebbe utilizzare sia string che const char * in tutto;).

+0

@Kornel Kisielewicz: Ma come è è inutile se salva un'allocazione di memoria, che può essere costosa se la stringa è lunga? Pensavo che C++ riguardasse "non pagare per quello che non usi". – Manuel

+0

@Manuel - viola il principio ASCIUTTO e ha tutte le trappole che derivano da quello –

+3

Come è correlato a ASCIUGARE? – Manuel

2

StringPiece mantiene un puntatore ai dati di stringa passati al suo costruttore. Quindi si basa sulla durata di quella stringa per essere più lunga di StringPiece. Questo è garantito se si utilizza StringPiece come parametro di funzione; non così se per esempio stai tenendo una copia della stringa in un membro della classe.

Non è così universale come std :: string, e non è sicuramente un sostituto per esso.

+0

Sì, non dovresti mai tenerne una copia. Penso che questo possa essere applicato banalmente facendo il suo copy ctor. e op = privato. Per non essere un sostituto universale di std :: string, sono d'accordo. Entrambi sono destinati a lavorare insieme. std :: string => uso generico; StringPiece => solo come parametro di funzione di sola lettura – Manuel

+0

Non consentirebbe l'assegnazione solo perché richiederei che tutti i metodi della classe siano dichiarati const, rinforzando il fatto che si tratta di un oggetto const. Suppongo che la pratica di dichiarare copy ctor e assegnazione a coppie sia l'unica ragione per non consentire un copy ctor. – jmucchiello

+0

@jmucchiello - E anche per impedire alle persone di conservare la propria copia della stringa e mantenerla in vita più a lungo che la funzione. Non penso che tu possa impedirlo, a meno che tu non disabiliti il ​​copy ctor. – Manuel

4

La domanda ha già avuto una risposta molto buona, ma per dare un po 'più di contesto, il pattern StringPiece è ampiamente utilizzato internamente a Google ed è stato per molti anni. È fortemente raccomandato nelle linee guida sulla codifica di Google, che è quasi sicuramente il motivo per cui Chrome (e successivamente Chromium) l'hanno adottato.

0

StringPiece è ottimo ma i pezzi non sono nulli. Se è necessario passare a interfacce di livello inferiore che accettano stringhe con terminazione nulla, è necessario copiare il copione in una stringa terminata da null.

(Non tutti hanno acquistato in STL o std :: string.)

8

po 'più tardi, ma ...

idea alla base StringPiece è molto buona. La classe può acquisire sia std::string e const char * e passarli a una funzione. Ecco un esempio:

void process(const StringRef s){ 
    // do something 
} 

process("Hello"); // const char * 
std::string s = "Hello"; 
process(s); // std::string 
process(std::string("Hello")); // std::string rvalue 

Se la funzione accettati std::string in realtà la creazione di un oggetto temporaneo se si passa const char * e tutto il char è copiato (per esempio con memcpy).

Inoltre non è necessario preoccuparsi della vita notturna, perché si sta passando StringRef a funzione/metodo.

ci sono tale classe in:

  • Google - StringPiece

  • spinta - boost :: string_ref

  • LLVM - stringRef

mia (incompleta) l'implementazione può essere vista qui:
https://github.com/nmmmnu/HM3/blob/master/include/stringref.h

Aggiornamento 2016:

In C++ 17, ci sono std::string_view. Non l'ho studiato nei dettagli, ma in generale ha la stessa idea. Anche simile alla mia implementazione ha constexpr c-tor, quindi puoi creare oggetti in fase di compilazione e usarlo insieme ad altre funzioni constexpr.

Problemi correlati