2010-01-31 2 views
12

Aus der Dokumentation der StringPiece class in Chromium's source code:Gibt es Gründe, warum das StringPiece/StringRef-Idiom nicht beliebter ist?

// 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. 

Beispiel:

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"); 
} 

dies eine wichtige und offensichtliche Optimierung wie so scheint, dass ich kann nicht verstehen, warum es nicht mehr weit verbreitet ist, und warum Eine Klasse, die StringPiece ähnlich ist, ist nicht bereits im Standard enthalten.

Gibt es irgendwelche Gründe, warum ich die Verwendung von string und char* Parameter in meinem eigenen Code mit dieser Klasse nicht ersetzen sollte? Gibt es so etwas schon in den C++ - Standardbibliotheken?

UPDATE. Ich habe gelernt, dass die Quelle von LLVM ein ähnliches Konzept verwendet: die StringRef Klasse.

+0

Ich mag dies als eine theoretische Idee. Ich frage mich, wie verwirrend es in der Praxis ohne "Training" wäre. – jmucchiello

+1

Alte Post, aber für zukünftige Leser sollte es beachten, wurde vorgeschlagen: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html –

Antwort

-7

Weil warum stören? Mit Kopie Elision und/oder Pass by Referenz, Speicherzuweisungen für std::string kann in der Regel ebenfalls vermieden werden.

Die Zeichenfolge Situation in C++ ist verwirrend genug, wie es ist, ohne noch mehr String-Klassen hinzuzufügen.

Wenn die Sprache von Grund auf neu entwickelt werden sollte oder wenn Abwärtskompatibilität kein Problem war, dann ist dies eine von vielen möglichen Verbesserungen, die zur String-Behandlung in C++ gemacht werden könnten. Aber jetzt, da wir sowohl bei char* als auch bei std::string stecken bleiben, würde das Hinzufügen einer stringref-style-Klasse in die Mischung viel Verwirrung mit begrenztem Nutzen verursachen.

Abgesehen davon, wird nicht der gleiche Effekt idiomatisch mit einem Paar Iteratoren erreicht? Wenn ich eine Folge von Zeichen übergeben möchte, egal ob sie zu einer Zeichenfolge oder einer char* gehören, warum sollte ich nicht einfach ein Paar Iteratoren verwenden, um sie zu begrenzen?

+3

Aber wenn Sie die Route "zwei Iteratoren" gehen, dann müssen Sie eine Klasse analog zu StringPiece erfinden, die Ihnen eine bequeme string-ähnliche Schnittstelle gibt. Und die erste Zeile Ihrer Funktionen wäre immer etwas wie "StringRange str (str_beg, str_end);".Für die beste Bewertung bisher akzeptiert. – Manuel

+0

Richtig über die bequeme string-ähnliche Schnittstelle, aber denken Sie daran, dass Iteratoren in C++ bereits idiomatisch sind. Ich sehe nicht, warum Ihre Funktionen einen String-Bereich von den Iteratoren erstellen müssten. Stattdessen sollte die gesamte Schnittstelle für die Zeichenfolgenbearbeitung als freie Funktionen für Iteratoren bereitgestellt werden. Die StringAlgo-Bibliothek von Boost behebt viel davon. – jalf

+0

Ich glaube nicht, dass Sie wirklich mögen würden, was Sie vorschlagen. Stellen Sie sich etwas so einfaches wie "strA + strB + strC" in Bezug auf Iteratoren vor. – Manuel

0

Der Standard versucht, sich von const char * zugunsten von string ganz wegzubewegen, daher ist es nutzlos, weitere Optionen für die Konvertierung hinzuzufügen.

Beachten Sie auch, dass ein schönes gebildetes Programm entweder string oder const char * allround verwenden sollte;).

+0

@Kornel Kisielewicz: Aber wie ist es nutzlos, wenn es eine Speicherzuweisung speichert, die teuer sein kann, wenn die Zeichenfolge lang ist? Ich dachte, in C++ ging es um "Zahlen Sie nicht für das, was Sie nicht verwenden". – Manuel

+0

@Manuel - es verstößt gegen das DRY-Prinzip und hat alle Gefahren, die von diesem kommen –

+3

Wie ist das mit DRY verwandt? – Manuel

2

StringPiece behält einen Zeiger auf die Zeichenfolge Daten, die an seinen Konstruktor übergeben wird. Daher hängt es von der Lebensdauer dieser Zeichenfolge ab, länger als die StringPiece zu sein. Dies ist garantiert, wenn Sie StringPiece als Funktionsparameter verwenden. nicht so, wenn Sie zum Beispiel eine Kopie der Zeichenfolge in einem Klassenmitglied aufbewahren.

Es ist nicht ganz so universell wie Std :: String, und es ist definitiv kein Ersatz für es.

+0

Ja, Sie sollten niemals eine Kopie davon behalten. Ich denke, das kann trivial erzwungen werden, indem man seine Kopie macht. und op = privat. Da ich kein universeller Ersatz für std :: string bin, stimme ich zu. Beide sollen zusammenarbeiten. std :: string => generische Verwendung; StringPiece => nur als schreibgeschützter Funktionsparameter – Manuel

+0

Ich würde die Zuweisung nur verbieten, weil ich verlangen müsste, dass alle Methoden der Klasse const deklariert werden, was verstärkt, dass dies ein const-Objekt ist. Ich nehme an, dass die Praxis, copy ctor und Zuweisung in Paaren zu deklarieren, der einzige Grund ist, keine Kopie ctor zuzulassen. – jmucchiello

+0

@jmucchiello - Und auch um zu verhindern, dass Menschen ihre eigene Kopie der Zeichenfolge speichern und länger am Leben erhalten als die Funktion. Ich glaube nicht, dass du das verhindern kannst, wenn du nicht den copy ctor deaktivierst. – Manuel

4

Die Frage wurde bereits sehr gut beantwortet, aber um mehr Kontext zu geben, ist das StringPiece Muster intern bei Google sehr weit verbreitet und ist seit vielen Jahren. Es wird dringend in den Codierungsrichtlinien von Google empfohlen, da Chrome (und anschließend Chromium) mit ziemlicher Sicherheit übernommen wird.

0

StringPiece ist großartig, aber die Stücke sind nicht null terminiert. Wenn Sie zu Interfaces auf niedrigerer Ebene übergehen müssen, die leere terminierte Strings verwenden, müssen Sie das stringpiece in eine nullterminierte Zeichenfolge kopieren.

(Nicht jeder hat in STL oder Std :: String gekauft.)

8

Bit später, aber ...

Idee hinter StringPiece ist sehr gut. Die Klasse kann sowohl std::string als auch const char * erfassen und an eine Funktion übergeben. Hier ein Beispiel:

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 

Wenn Funktion std::string akzeptierte Sie tatsächlich ein temporäres Objekt zu schaffen, wenn Sie const char * und ganz char passieren wird kopiert (zB mit memcpy).

Sie müssen sich auch keine Gedanken über die Lebenszeit machen, weil Sie StringRef an Funktion/Methode übergeben.

Es gibt solche Klasse in:

  • Google - StringPiece

  • Schub - boost :: string_ref

  • LLVM - StringRef

Meine eigene (unvollständig) Implementierung kann hier gesehen werden:
https://github.com/nmmmnu/HM3/blob/master/include/stringref.h

-Update 2016:

In C++ 17 gibt es std::string_view. Ich habe es nicht im Detail studiert, aber im Allgemeinen hat es die gleiche Idee. Auch ähnlich wie meine Implementierung es constexpr c-tor, so können Sie Objekte zur Kompilierzeit erstellen und verwenden Sie es zusammen mit anderen constexpr Funktionen.

Verwandte Themen