Differenze tra C ++ string == e compare ()?


363

Ho appena letto alcuni consigli sull'utilizzo

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

if( !s.compare(t) ) 
{

invece di

if( s == t )
{

Uso quasi sempre l'ultimo perché ci sono abituato e mi sembra naturale, più leggibile. Non sapevo nemmeno che esistesse una funzione di confronto separata. Per essere più precisi, ho pensato che == avrebbe chiamato compare ().

Quali sono le differenze? In quali contesti un modo dovrebbe essere favorito dall'altro?

Sto prendendo in considerazione solo i casi in cui ho bisogno di sapere se una stringa ha lo stesso valore di un'altra stringa.


5
Il primo tornerà vero dove il secondo restituirà falso, e viceversa.
Viktor Sehr,

56
Il primo è appena leggibile mentre il secondo è facilmente leggibile e comprensibile.
Matthieu M.

3
Uso le funzioni "confronta" in questo modo: if(x.compare(y) == 0)<- segno di uguale, è uguale. L'utilizzo dell'IMO !serve solo a rendere illeggibile il codice.
R. Martinho Fernandes,

1
Va notato che == non funzionerà per te in ogni caso. stringa sovraccarica l'operatore di eseguire un confronto, quindi == equivale a chiamare un confronto. In alternativa, se lo provi su oggetti che non sovraccaricano l'operatore ==, confronterai il loro indirizzo in memoria e non i loro componenti interni. Chiamare compare è più "sicuro". Nel caso di usare std :: string, però, stai bene.
DCurro,

Una differenza: comparereturn -1if sè inferiore a te +1if sè maggiore di twhile ==return true/false. I numeri interi diversi da zero sono trueed 0è false.
GyuHyeon Choi,

Risposte:


450

Questo è ciò che lo standard ha da dire operator==

21.4.8.2 operatore ==

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

Restituisce: lhs.compare (rhs) == 0.

Sembra che non ci sia molta differenza!


5
Nota per i lettori: si prega di leggere la risposta di Frédéric Hamidi per i dettagli sulla questione perché ci sono differenze rilevanti. Anche se sono contento, Bo Persson dimostra che i due test restituiranno sicuramente lo stesso valore. !s.compare(t)e s == trestituirà lo stesso valore, ma la funzione di confronto fornisce più informazioni di s == t, ed s == tè più leggibile quando non ti interessa come le stringhe differiscono ma solo se differiscono.
cdgraham,

143

std :: string :: compare () restituisce un int:

  • uguale a zero se se tsono uguali,
  • inferiore a zero se sè inferiore a t,
  • maggiore di zero se sè maggiore di t.

Se vuoi che il tuo primo frammento di codice sia equivalente al secondo, dovresti effettivamente leggere:

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

L'operatore di uguaglianza verifica solo l'uguaglianza (da cui il suo nome) e restituisce a bool.

Per approfondire i casi d'uso, compare()può essere utile se sei interessato a come le due stringhe si relazionano tra loro (meno o più) quando risultano diverse. PlasmaHH menziona giustamente gli alberi e potrebbe anche essere, per esempio, un algoritmo di inserimento di stringhe che mira a mantenere il contenitore ordinato, un algoritmo di ricerca dicotomica per il contenitore di cui sopra, e così via.

EDIT: Come sottolinea Steve Jessop nei commenti, compare()è molto utile per gli algoritmi di ricerca rapida e binaria. I tipi naturali e le ricerche dicotomiche possono essere implementate solo con std :: less .


nota che questo comportamento è spesso utile quando hai a che fare con alberi o creature simili ad alberi.
PlasmaHH,

In verità lo è, stavo solo sottolineando le differenze tra il metodo e l'operatore di uguaglianza :)
Frédéric Hamidi,

"In quali contesti un modo dovrebbe essere preferito all'altro?" mi fa solo pensare che l'OP non possa pensare a possibili casi d'uso per compare ().
PlasmaHH,

2
"se sei interessato a come le due stringhe si relazionano l'una con l'altra" - sebbene C ++ idiomatico per questo sia usare un ordine debole e rigoroso (come std::less, che è anche un ordine totale in questo caso) piuttosto che un comparatore a tre vie . compare()è per le operazioni modellate su std::qsorte std::bsearch, a differenza di quelle modellate su std:sorte std::lower_bound.
Steve Jessop,

30

comparepresenta sovraccarichi per il confronto di sottostringhe. Se stai confrontando intere stringhe dovresti semplicemente usare l' ==operatore (e se chiama compareo meno è praticamente irrilevante).


30

Internamente, string::operator==()sta usando string::compare(). Fare riferimento a: CPlusPlus -string::operator==()

Ho scritto una piccola applicazione per confrontare le prestazioni e apparentemente se compili ed esegui il tuo codice in ambiente di debug string::compare()è leggermente più veloce di string::operator==(). Tuttavia, se compili ed esegui il tuo codice in ambiente Release, entrambi sono praticamente uguali.

Cordiali saluti, ho eseguito 1.000.000 di iterazioni per arrivare a tale conclusione.

Per dimostrare perché nell'ambiente di debug la stringa :: compare è più veloce, sono andato all'assemblaggio ed ecco il codice:

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)

Puoi vedere che in string :: operator == (), deve eseguire operazioni extra (aggiungi esp, 8 e movzx edx, al)

COMUNICATO STAMPA

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)

Entrambi i codici assembly sono molto simili in quanto il compilatore esegue l'ottimizzazione.

Infine, a mio avviso, il guadagno in termini di prestazioni è trascurabile, quindi lascerei davvero allo sviluppatore decidere su quale sia il preferito poiché entrambi ottengono lo stesso risultato (specialmente quando si tratta di build di rilascio).


10
"molto simile" ... non vedo alcuna differenza, vero?
xtofl,

nemmeno io ... sono la stessa cosa. non c'è differenza
Wagner Patriota il

1
@xtofl dall'esempio di Tony i codici generati sono identici nella build di rilascio, sono diversi nelle build di debug.
JulianHarty,

6

compare()è equivalente a strcmp (). ==è un semplice controllo dell'uguaglianza. compare()pertanto restituisce un int, ==è un valore booleano.


5

compare()tornerà false(bene 0) se le stringhe sono uguali.

Quindi non prendere lo scambio l'uno con l'altro alla leggera.

Usa qualunque cosa renda il codice più leggibile.


3

Se vuoi solo controllare l'uguaglianza delle stringhe, usa l'operatore ==. Determinare se due stringhe sono uguali è più semplice che trovare un ordinamento (che è ciò che compare () fornisce), quindi nel tuo caso potrebbe essere meglio usare l'operatore di uguaglianza.

Risposta più lunga: l'API fornisce un metodo per verificare l'uguaglianza delle stringhe e un metodo per controllare l'ordinamento delle stringhe. Volete l'uguaglianza delle stringhe, quindi usate l'operatore di uguaglianza (in modo che le vostre aspettative e quelle degli implementatori della libreria siano allineate). Se le prestazioni sono importanti, potreste voler testare entrambi i metodi e trovare il più veloce.


2

Supponiamo di considerare due stringhe s e t.
Dai loro dei valori.
Quando li confronti usando (s == t) restituisce un valore booleano (vero o falso, 1 o 0).
Ma quando si confronta utilizzando s.compare (t) , l'espressione restituisce un valore
(i) 0 - se s e t sono uguali
(ii) <0 - o se il valore del primo carattere ineguagliato in s è inferiore a quello di t o la lunghezza di s è inferiore a quella di t.
(iii) > 0 - se il valore del primo carattere ineguagliato in t è inferiore a quello di se la lunghezza di t è inferiore a quella di s.


1

Una cosa che non è coperta qui è che dipende se confrontiamo stringa con stringa c, stringa c con stringa o stringa con stringa.

Una grande differenza è che per il confronto tra due stringhe viene verificata l'uguaglianza prima di eseguire il confronto e ciò rende l'operatore == più veloce di un confronto.

ecco il confronto come lo vedo su g ++ Debian 7

// 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; }

il codice è formattato e mostrato formattato nell'editor. Il display ha sbagliato. apri basic_string.h e cerca operator == sul tuo sistema operativo. Il codice non è mio è standard, il fatto che il controllo delle dimensioni sia ciò che manca in questo thread. Vedo anche che molte persone concordano con informazioni errate che sfidano l'utilità di Stack Overflow.
Dragos,
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.