¿Diferencias entre cadena C++ == y comparar()?

Resuelto Klaim asked hace 12 años • 9 respuestas

Acabo de leer algunas recomendaciones sobre el uso.

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

if( !s.compare(t) ) 
{

en lugar de

if( s == t )
{

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

¿Cuáles son las diferencias? ¿En qué contextos debería privilegiarse una forma sobre la otra?

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

Klaim avatar Feb 06 '12 17:02 Klaim
Aceptado

Esto es lo que la norma tiene que decir sobreoperator==

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 avatar Feb 06 '2012 11:02 Bo Persson

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, debería decir:

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

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

Puede resultar útil profundizar en los casos de uso compare()si está interesado en cómo se relacionan las dos cadenas entre sí (menor o mayor) cuando resultan ser diferentes. PlasmaHH menciona con razón árboles, y también podría ser, digamos, 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, etc.

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

Frédéric Hamidi avatar Feb 06 '2012 10:02 Frédéric Hamidi

Internamente, string::operator==()está usando 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, es string::compare()un poco más rápido que string::operator==(). Sin embargo, si compila y ejecuta su código en el entorno de lanzamiento, ambos son prácticamente iguales.

Para su información, realicé 1.000.000 de iteraciones para llegar a esa conclusión.

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

DEPURACIÓN CONSTRUCCIÓN

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)  

cadena::comparar()

            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)

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

LANZAR 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)  

cadena::comparar()

            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 ensambladores son muy similares ya que el compilador realiza la optimización.

Finalmente, en mi opinión, la ganancia de rendimiento es insignificante, por lo que realmente dejaría que el desarrollador decida cuál es el preferido, ya que ambos logran el mismo resultado (especialmente cuando se trata de una versión de lanzamiento).

Tony Mulia avatar Dec 22 '2015 05:12 Tony Mulia

comparetiene sobrecargas para comparar subcadenas. Si está comparando cadenas completas, debería usar ==operador (y si llama compareo no es prácticamente irrelevante).

Cat Plus Plus avatar Feb 06 '2012 10:02 Cat Plus Plus