web-dev-qa-db-de.com

Soll ich einen std :: string mit "string" oder "string" vergleichen?

Betrachten Sie dieses Code-Snippet:

bool foo(const std::string& s) {
    return s == "hello"; // comparing against a const char* literal
}

bool bar(const std::string& s) {
    return s == "hello"s; // comparing against a std::string literal
}

Bei auf den ersten Blick sieht es so aus, als würde ein Vergleich mit einem const char* Weniger Montageanweisungen erfordern1, da die Verwendung eines String-Literals zu einer direkten Konstruktion des std::string führt.

( EDIT: Wie in den Antworten ausgeführt, habe ich vergessen, dass effektiv s.compare(const char*) in foo() aufgerufen wird, also Natürlich findet in diesem Fall keine In-Place-Konstruktion statt. Streichen Sie daher einige Zeilen weiter unten aus. )

Betrachten Sie jedoch die Referenz operator==(const char*, const std::string&) :

Alle Vergleiche werden über die Elementfunktion compare() durchgeführt.

Nach meinem Verständnis bedeutet dies, dass wir ohnehin einen std::string Erstellen müssen, um den Vergleich durchzuführen, sodass ich vermute, dass der Overhead am Ende der gleiche sein wird (obwohl er durch den Aufruf von operator==).

  • Welchen der Vergleiche sollte ich bevorzugen?
  • Hat eine Version Vorteile gegenüber der anderen (möglicherweise in bestimmten Situationen)?

1 Ich bin mir bewusst, dass weniger Montageanweisungen nicht unbedingt schnelleren Code bedeuten, aber ich möchte hier nicht auf Mikro-Benchmarking eingehen.

44
andreee

Weder.

Wenn Sie klug sein wollen, vergleichen Sie mit "string"sv , was ein std::string_view .


Beim Vergleich mit einem Literal wie "string" führt zu keinem Zuordnungsaufwand, sondern wird als nullterminierte Zeichenfolge mit allen damit verbundenen Nachteilen behandelt: Keine Toleranz für eingebettete Nullen, und Benutzer müssen den Nullterminator beachten.

"string"s führt eine Zuordnung durch, mit Ausnahme von Small-String-Optimierung oder Zuweisungselision . Außerdem wird dem Operator die Länge des Literal übergeben, es muss nicht gezählt werden, und es werden eingebettete Nullen zugelassen.

Und schließlich mit "string"sv kombiniert die Vorteile beider anderen Ansätze und vermeidet deren individuelle Nachteile. Auch ein std::string_view ist ein viel einfacheres Tier als ein std::string, insbesondere wenn letzteres wie alle modernen SSO verwendet.


Zumindest seit C++ 14 (das im Allgemeinen das Eliminieren von Zuordnungen ermöglichte) konnten Compiler theoretisch alle Optionen bis zur letzten optimieren, wenn ausreichende Informationen (für das Beispiel allgemein verfügbar) und Aufwand unter der als ob-Regel) vorhanden waren . Wir sind aber noch nicht da.

66
Deduplicator

Nein, compare() erfordert keine Konstruktion eines std::string zum const char* Operanden.

Sie verwenden Überladung # 4 hier .

Der Vergleich mit String-Literal ist die "kostenlose" Version, die Sie suchen. Instanziieren eines std::string hier ist völlig unnötig.

Nach meinem Verständnis bedeutet dies, dass wir ohnehin einen std::string Erstellen müssen, um den Vergleich durchzuführen, sodass ich vermute, dass der Overhead am Ende der gleiche sein wird (obwohl er durch den Aufruf von operator==).

Hier geht diese Argumentation schief. std::compare muss seinen Operanden nicht als nullterminierte Zeichenfolge im C-Stil zuweisen, um zu funktionieren. Nach einer der Überlastungen:

int compare( const CharT* s ) const; // (4)

4) Vergleicht diese Zeichenfolge mit der nullterminierten Zeichenfolge, die an dem Zeichen beginnt, auf das s mit der Länge Traits::length(s) zeigt.

Obwohl die Zuweisung oder Nichtzuweisung ein Implementierungsdetail ist, erscheint es nicht sinnvoll, dass ein Sequenzvergleich dies tun würde.