Unterschiede zwischen C ++ string == und compare ()?

363

Ich habe gerade einige Empfehlungen zur Verwendung gelesen

std::string s = get_string();
std::string t = another_string();

if( !s.compare(t) ) 
{

anstatt

if( s == t )
{

Ich benutze fast immer den letzten, weil ich daran gewöhnt bin und er sich natürlich und lesbarer anfühlt. Ich wusste nicht einmal, dass es eine separate Vergleichsfunktion gibt. Genauer gesagt dachte ich, == würde compare () aufrufen.

Was sind die Unterschiede? In welchen Kontexten sollte ein Weg dem anderen vorgezogen werden?

Ich betrachte nur die Fälle, in denen ich wissen muss, ob eine Zeichenfolge den gleichen Wert wie eine andere Zeichenfolge hat.

Klaim
quelle
5
Der erste gibt true zurück, während der letztere false zurückgibt, und umgekehrt.
Viktor Sehr
56
Der erste ist kaum lesbar, während der letztere leicht zu lesen und zu verstehen ist.
Matthieu M.
3
Ich benutze "Vergleichs" -Funktionen wie folgt: if(x.compare(y) == 0)<- Gleichheitszeichen, es ist gleich. Die Verwendung von IMO !dient nur dazu, Code unlesbar zu machen.
R. Martinho Fernandes
1
Es sollte beachtet werden, dass == nicht in jedem Fall für Sie funktionieren wird. Die Zeichenfolge überlastet den Operator, um einen Vergleich durchzuführen. == entspricht dem Aufrufen eines Vergleichs. Wenn Sie dies bei Objekten versuchen, die den Operator == nicht überladen, vergleichen Sie alternativ deren Adresse im Speicher und nicht deren interne Komponenten. Das Aufrufen von compare ist "sicherer". Bei Verwendung von std :: string ist dies jedoch in Ordnung.
DCurro
Ein Unterschied: comparereturn -1if sist niedriger als tund +1if sist größer als twhile ==return true/false. Ganzzahlen ungleich Null sind trueund 0sind false.
GyuHyeon Choi

Antworten:

450

Darüber sagt der Standard operator==

21.4.8.2 operator ==

template<class charT, class traits, class Allocator>
bool operator==(const basic_string<charT,traits,Allocator>& lhs,
                const basic_string<charT,traits,Allocator>& rhs) noexcept;

Rückgabe: lhs.compare (rhs) == 0.

Es scheint, als gäbe es keinen großen Unterschied!

Bo Persson
quelle
5
Hinweis für die Leser: Bitte lesen Sie die Antwort von Frédéric Hamidi, um Einzelheiten zu diesem Thema zu erfahren, da es relevante Unterschiede gibt. Obwohl ich froh bin, dass Bo Persson zeigt, dass die beiden Tests definitiv den gleichen Wert liefern werden. !s.compare(t)und s == tgibt den gleichen Wert zurück, aber die Vergleichsfunktion liefert mehr Informationen als s == tund s == tist besser lesbar, wenn Sie sich nicht darum kümmern, wie sich die Zeichenfolgen unterscheiden, sondern nur, wenn sie sich unterscheiden.
CDgraham
143

std :: string :: compare () gibt Folgendes zurück int:

  • gleich Null, wenn sund tgleich sind,
  • kleiner als Null, wenn skleiner als istt ,
  • größer als Null, wenn sgrößer als ist t.

Wenn Sie möchten, dass Ihr erstes Code-Snippet dem zweiten entspricht, sollte es tatsächlich lauten:

if (!s.compare(t)) {
    // 's' and 't' are equal.
}

Der Gleichheitsoperator prüft nur auf Gleichheit (daher sein Name) und gibt a zurück bool.

Eine Erläuterung der Anwendungsfälle compare()kann hilfreich sein, wenn Sie daran interessiert sind, wie sich die beiden Zeichenfolgen zueinander verhalten (kleiner oder größer), wenn sie sich zufällig unterscheiden. PlasmaHH erwähnt zu Recht Bäume, und es könnte sich beispielsweise auch um einen Algorithmus zum Einfügen von Zeichenfolgen handeln, der darauf abzielt, den Container sortiert zu halten, einen dichotomischen Suchalgorithmus für den oben genannten Container usw.

BEARBEITEN: Wie Steve Jessop in den Kommentaren hervorhebt, compare()ist es am nützlichsten für schnelle Sortier- und binäre Suchalgorithmen. Natürliche Sortierungen und dichotomische Suchen können nur mit std :: less implementiert werden .

Frédéric Hamidi
quelle
Beachten Sie, dass dieses Verhalten häufig beim Umgang mit Bäumen oder baumartigen Kreaturen hilfreich ist.
PlasmaHH
In der Tat habe ich nur auf die Unterschiede zwischen der Methode und dem Gleichheitsoperator hingewiesen :)
Frédéric Hamidi
"In welchen Kontexten sollte ein Weg dem anderen vorgezogen werden?" Ich denke nur, dass das OP nicht an mögliche Anwendungsfälle für compare () denken kann.
PlasmaHH
2
"Wenn Sie daran interessiert sind, wie die beiden Zeichenfolgen zueinander in Beziehung stehen" - obwohl das idiomatische C ++ dafür darin besteht, eine streng schwache Reihenfolge (wie std::lessin diesem Fall auch eine Gesamtreihenfolge) anstelle eines Drei-Wege-Komparators zu verwenden . compare()ist für Operationen, die nach std::qsortund modelliert sind std::bsearch, im Gegensatz zu Operationen , die nach std:sortund modelliert sind std::lower_bound.
Steve Jessop
30

comparehat Überladungen zum Vergleichen von Teilzeichenfolgen. Wenn Sie ganze Zeichenfolgen vergleichen, sollten Sie nur den ==Operator verwenden (und ob er aufruft compareoder nicht, ist ziemlich irrelevant).

Cat Plus Plus
quelle
30

Intern string::operator==()verwendet string::compare(). Bitte beachten Sie: CPlusPlus -string::operator==()

Ich habe eine kleine Anwendung geschrieben, um die Leistung zu vergleichen, und anscheinend ist die Anwendung string::compare()etwas schneller als , wenn Sie Ihren Code in einer Debug-Umgebung kompilieren und ausführen string::operator==(). Wenn Sie Ihren Code jedoch in der Release-Umgebung kompilieren und ausführen, sind beide ziemlich gleich.

Zu Ihrer Information, ich habe 1.000.000 Iterationen ausgeführt, um zu einer solchen Schlussfolgerung zu gelangen.

Um zu beweisen, warum in der Debug-Umgebung der String :: compare schneller ist, bin ich zur Assembly gegangen und hier ist der Code:

DEBUG BUILD

string :: operator == ()

        if (str1 == str2)
00D42A34  lea         eax,[str2]  
00D42A37  push        eax  
00D42A38  lea         ecx,[str1]  
00D42A3B  push        ecx  
00D42A3C  call        std::operator==<char,std::char_traits<char>,std::allocator<char> > (0D23EECh)  
00D42A41  add         esp,8  
00D42A44  movzx       edx,al  
00D42A47  test        edx,edx  
00D42A49  je          Algorithm::PerformanceTest::stringComparison_usingEqualOperator1+0C4h (0D42A54h)  

string :: compare ()

            if (str1.compare(str2) == 0)
00D424D4  lea         eax,[str2]  
00D424D7  push        eax  
00D424D8  lea         ecx,[str1]  
00D424DB  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::compare (0D23582h)  
00D424E0  test        eax,eax  
00D424E2  jne         Algorithm::PerformanceTest::stringComparison_usingCompare1+0BDh (0D424EDh)

Sie können sehen, dass in string :: operator == () zusätzliche Operationen ausgeführt werden müssen (add esp, 8 und movzx edx, al).

FREIGABE BAUEN

string :: operator == ()

        if (str1 == str2)
008533F0  cmp         dword ptr [ebp-14h],10h  
008533F4  lea         eax,[str2]  
008533F7  push        dword ptr [ebp-18h]  
008533FA  cmovae      eax,dword ptr [str2]  
008533FE  push        eax  
008533FF  push        dword ptr [ebp-30h]  
00853402  push        ecx  
00853403  lea         ecx,[str1]  
00853406  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::compare (0853B80h)  

string :: compare ()

            if (str1.compare(str2) == 0)
    00853830  cmp         dword ptr [ebp-14h],10h  
    00853834  lea         eax,[str2]  
    00853837  push        dword ptr [ebp-18h]  
    0085383A  cmovae      eax,dword ptr [str2]  
    0085383E  push        eax  
    0085383F  push        dword ptr [ebp-30h]  
    00853842  push        ecx  
00853843  lea         ecx,[str1]  
00853846  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::compare (0853B80h)

Beide Assembly-Codes sind sehr ähnlich, da der Compiler die Optimierung durchführt.

Schließlich ist meiner Meinung nach der Leistungsgewinn vernachlässigbar, daher würde ich es wirklich dem Entwickler überlassen, zu entscheiden, welches das bevorzugte ist, da beide das gleiche Ergebnis erzielen (insbesondere wenn es sich um ein Release-Build handelt).

Tony Mulia
quelle
10
'sehr ähnlich' ... ich sehe keinen Unterschied, oder?
xtofl
ich auch nicht ... sie sind das gleiche. Es gibt keinen Unterschied
Wagner Patriota
1
@xtofl aus Tonys Beispiel Die generierten Codes sind im Release-Build identisch, sie unterscheiden sich in den Debug-Builds.
JulianHarty
6

compare()entspricht strcmp (). ==ist eine einfache Gleichheitsprüfung. compare()Daher wird ein int, ==ist ein Boolescher Wert zurückgegeben.

ckruse
quelle
5

compare()wird zurückkehren false( na ja ,0 wenn die Zeichenfolgen gleich sind.

Nehmen Sie es also nicht leicht, einen gegen den anderen auszutauschen.

Verwenden Sie, was den Code lesbarer macht.

Luchian Grigore
quelle
3

Wenn Sie nur die Gleichheit der Zeichenfolgen überprüfen möchten, verwenden Sie den Operator ==. Das Ermitteln, ob zwei Zeichenfolgen gleich sind, ist einfacher als das Finden einer Reihenfolge (was compare () ergibt). In Ihrem Fall ist es daher möglicherweise leistungsmäßig besser, den Gleichheitsoperator zu verwenden.

Längere Antwort: Die API bietet eine Methode zum Überprüfen der Zeichenfolgengleichheit und eine Methode zum Überprüfen der Zeichenfolgenreihenfolge. Wenn Sie eine Zeichenfolgengleichheit wünschen, verwenden Sie den Gleichheitsoperator (damit Ihre Erwartungen und die der Bibliotheksimplementierer übereinstimmen). Wenn die Leistung wichtig ist, möchten Sie möglicherweise beide Methoden testen und die schnellste finden.

RobH
quelle
2

Angenommen, Sie betrachten zwei Zeichenfolgen s und t.
Gib ihnen einige Werte.
Wenn Sie sie mit (s == t) vergleichen , wird ein boolescher Wert zurückgegeben (true oder false, 1 oder 0).
Wenn Sie jedoch mit s.compare (t) vergleichen , gibt der Ausdruck einen Wert
(i) 0 zurück - wenn s und t gleich sind
(ii) <0 - entweder wenn der Wert des ersten nicht übereinstimmenden Zeichens in s kleiner als der von ist t oder die Länge von s ist kleiner als die von t.
(iii) > 0 - entweder wenn der Wert des ersten nicht übereinstimmenden Zeichens in t kleiner als der von s ist oder die Länge von t kleiner als der von s ist.

narutoUzumaki21
quelle
1

Eine Sache, die hier nicht behandelt wird, ist, dass es davon abhängt, ob wir String mit C-String, C-String mit String oder String mit String vergleichen.

Ein Hauptunterschied besteht darin, dass beim Vergleichen von zwei Zeichenfolgen die Größengleichheit vor dem Vergleichen überprüft wird und der Operator == dadurch schneller als ein Vergleich ist.

Hier ist der Vergleich, wie ich ihn auf g ++ Debian 7 sehe

// operator ==
  /**
   *  @brief  Test equivalence of two strings.
   *  @param __lhs  First string.
   *  @param __rhs  Second string.
   *  @return  True if @a __lhs.compare(@a __rhs) == 0.  False otherwise.
   */
  template<typename _CharT, typename _Traits, typename _Alloc>
    inline bool
    operator==(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
           const basic_string<_CharT, _Traits, _Alloc>& __rhs)
    { return __lhs.compare(__rhs) == 0; }

  template<typename _CharT>
    inline
    typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value, bool>::__type
    operator==(const basic_string<_CharT>& __lhs,
           const basic_string<_CharT>& __rhs)
    { return (__lhs.size() == __rhs.size()
          && !std::char_traits<_CharT>::compare(__lhs.data(), __rhs.data(),
                            __lhs.size())); }

  /**
   *  @brief  Test equivalence of C string and string.
   *  @param __lhs  C string.
   *  @param __rhs  String.
   *  @return  True if @a __rhs.compare(@a __lhs) == 0.  False otherwise.
   */
  template<typename _CharT, typename _Traits, typename _Alloc>
    inline bool
    operator==(const _CharT* __lhs,
           const basic_string<_CharT, _Traits, _Alloc>& __rhs)
    { return __rhs.compare(__lhs) == 0; }

  /**
   *  @brief  Test equivalence of string and C string.
   *  @param __lhs  String.
   *  @param __rhs  C string.
   *  @return  True if @a __lhs.compare(@a __rhs) == 0.  False otherwise.
   */
  template<typename _CharT, typename _Traits, typename _Alloc>
    inline bool
    operator==(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
           const _CharT* __rhs)
    { return __lhs.compare(__rhs) == 0; }
Dragos
quelle
Code wird formatiert und im Editor formatiert angezeigt. Display hat es falsch verstanden. Öffnen Sie basic_string.h und suchen Sie auf Ihrem Betriebssystem nach operator ==. Der Code ist nicht meins ist Standard, die Tatsache, dass die Größenprüfung das ist, was in diesem Thread fehlt. Ich sehe auch, dass viele Leute mit falschen Informationen einverstanden sind, die dem Nutzen von Stack Overflow widersprechen.
Dragos