¿Diferencias entre C ++ string == y compare ()?

363

Acabo de leer algunas recomendaciones sobre el uso

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

if( !s.compare(t) ) 
{

en vez de

if( s == t )
{

Casi siempre uso el último porque estoy acostumbrado y se siente natural, más legible. Ni siquiera sabía que había una función de comparación separada. Para ser más preciso, pensé que == llamaría a compare ().

¿Cuáles son las diferencias? ¿En qué contextos se debe favorecer un camino al otro?

Solo estoy considerando los casos en los que necesito saber si una cadena tiene el mismo valor que otra cadena.

Klaim
fuente
55
El primero devolverá verdadero donde el último devuelve falso, y viceversa.
Viktor Sehr
56
El primero es apenas legible, mientras que el segundo es fácil de leer y comprender.
Matthieu M.
3
Uso funciones de "comparación" como esta: if(x.compare(y) == 0)<- signo igual, es igual. El uso de IMO !solo sirve para hacer que el código sea ilegible.
R. Martinho Fernandes
1
Cabe señalar que == no va a funcionar para usted en todos los casos. string sobrecarga al operador para realizar una comparación, por lo que == es lo mismo que llamar a una comparación. Alternativamente, si prueba esto en objetos que no sobrecargan el operador ==, comparará su dirección en la memoria y no sus componentes internos. Llamar a comparar es más "seguro". Sin embargo, en el caso de usar std :: string, estás bien.
DCurro
Una diferencia: comparedevuelve -1if ses menor que ty +1if ses mayor que tmientras que ==return true/false. Los enteros distintos de cero son truey 0son false.
GyuHyeon Choi

Respuestas:

450

Esto es lo que la norma tiene que decir sobre operator==

21.4.8.2 operador ==

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

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

¡Parece que no hay mucha diferencia!

Bo Persson
fuente
55
Nota para los lectores: Lea la respuesta de Frédéric Hamidi para obtener detalles sobre el tema porque existen diferencias relevantes. Aunque me alegro de que Bo Persson demuestre que las dos pruebas definitivamente devolverán el mismo valor. !s.compare(t)y s == tdevolverá el mismo valor, pero la función de comparación proporciona más información que s == t, y s == tes más legible cuando no le importa cómo difieren las cadenas, pero solo si difieren.
cdgraham
143

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

  • igual a cero si sy tson iguales,
  • menor que cero si ses menor que t,
  • mayor que cero si ses mayor que t.

Si desea que su primer fragmento de código sea equivalente al segundo, en realidad debería leer:

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

El operador de igualdad solo prueba la igualdad (de ahí su nombre) y devuelve a bool.

Para elaborar sobre los casos de uso, compare()puede ser útil si está interesado en cómo las dos cadenas se relacionan entre sí (menor o mayor) cuando son diferentes. PlasmaHH menciona con razón los árboles, y también podría ser, por ejemplo, un algoritmo de inserción de cadenas que tiene como objetivo mantener el contenedor ordenado, un algoritmo de búsqueda dicotómica para el contenedor antes mencionado, y así sucesivamente.

EDITAR: Como señala Steve Jessop en los comentarios, compare()es más útil para la clasificación rápida y los algoritmos de búsqueda binaria. Los tipos naturales y las búsquedas dicotómicas se pueden implementar con solo std :: less .

Frédéric Hamidi
fuente
Tenga en cuenta que este comportamiento a menudo es útil cuando se trata de árboles o criaturas similares a árboles.
PlasmaHH
De hecho, solo estaba señalando las diferencias entre el método y el operador de igualdad :)
Frédéric Hamidi
"¿En qué contextos se debe favorecer de una manera a la otra?" solo me hace pensar que el OP no puede pensar en posibles casos de uso para compare ().
PlasmaHH
2
"si está interesado en cómo se relacionan las dos cadenas entre sí", aunque C ++ idiomático para esto es usar un orden débil estricto (como std::less, que también es un orden total en este caso) en lugar de un comparador de tres vías . compare()es para operaciones modeladas en std::qsorty std::bsearch, a diferencia de aquellas modeladas en std:sorty std::lower_bound.
Steve Jessop
30

comparetiene sobrecargas para comparar subcadenas. Si está comparando cadenas enteras, solo debe usar el ==operador (y si llama compareo no es prácticamente irrelevante).

Cat Plus Plus
fuente
30

Internamente, string::operator==()está utilizando string::compare(). Consulte: CPlusPlus -string::operator==()

Escribí una pequeña aplicación para comparar el rendimiento, y aparentemente si compilas y ejecutas tu código en un entorno de depuración string::compare()es un poco más rápido que string::operator==(). Sin embargo, si compila y ejecuta su código en el entorno Release, ambos son más o menos lo mismo.

Para su información, ejecuté 1,000,000 de iteraciones para llegar a tal conclusión.

Para demostrar por qué en el entorno de depuración, string :: compare es más rápido, fui al ensamblado y aquí está el código:

DEPURAR CONSTRUIR

cadena :: operador == ()

        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)

Puede ver que en string :: operator == (), tiene que realizar operaciones adicionales (agregue esp, 8 y movzx edx, al)

LANZAMIENTO CONSTRUIR

cadena :: operador == ()

        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)

Ambos códigos de ensamblaje son muy similares ya que el compilador realiza la optimización.

Finalmente, en mi opinión, la ganancia de rendimiento es insignificante, por lo tanto, realmente le dejaría al desarrollador decidir cuál es la preferida, ya que ambas logran el mismo resultado (especialmente cuando se trata de la versión de lanzamiento).

Tony Mulia
fuente
10
'muy similar' ... no veo diferencia, ¿verdad?
xtofl
yo tampoco ... son lo mismo. no hay diferencia
Wagner Patriota
1
@xtofl del ejemplo de Tony, los códigos generados son idénticos en la versión de lanzamiento, son diferentes en las versiones de depuración.
JulianHarty
6

compare()es equivalente a strcmp (). ==es simple comprobación de igualdad. compare()por lo tanto, devuelve un int, ==es un booleano.

ckruse
fuente
5

compare()volverá false(bueno,0 ) si las cadenas son iguales.

Por lo tanto, no tome intercambiar uno por el otro a la ligera.

Use lo que haga que el código sea más legible.

Luchian Grigore
fuente
3

Si solo desea verificar la igualdad de la cadena, use el operador ==. Determinar si dos cadenas son iguales es más simple que encontrar un orden (que es lo que compara () da), por lo que podría ser mejor en términos de rendimiento en su caso utilizar el operador de igualdad.

Respuesta más larga: la API proporciona un método para verificar la igualdad de la cadena y un método para verificar el orden de las cadenas. Si desea la igualdad de cadenas, utilice el operador de igualdad (para que sus expectativas y las de los implementadores de la biblioteca se alineen). Si el rendimiento es importante, entonces puede probar ambos métodos y encontrar el más rápido.

RobH
fuente
2

Supongamos considerar dos cadenas s y t.
Dales algunos valores.
Cuando los compara usando (s == t) , devuelve un valor booleano (verdadero o falso, 1 o 0).
Pero cuando compara usando s.compare (t) , la expresión devuelve un valor
(i) 0 , si syt son iguales
(ii) <0 , ya sea si el valor del primer carácter no coincidente en s es menor que el de to la longitud de s es menor que la de t.
(iii) > 0 : si el valor del primer carácter no coincidente en t es menor que el de s o la longitud de t es menor que la de s.

narutoUzumaki21
fuente
1

Una cosa que no se cubre aquí es que depende si comparamos cadena con cadena c, cadena con cadena o cadena con cadena.

Una diferencia importante es que para comparar dos cadenas, la igualdad de tamaño se verifica antes de hacer la comparación y eso hace que el operador == sea más rápido que una comparación.

Aquí está la comparación tal como la veo en 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; }
Dragos
fuente
el código se formatea y se muestra formateado en el editor. La pantalla se equivocó. abra basic_string.h y busque operator == en su sistema operativo. El código no es mío es estándar, el hecho de que la comprobación de tamaño es lo que falta en este hilo. También veo que muchas personas están de acuerdo con la información incorrecta que desafía la utilidad de Stack Overflow.
Dragos