¿Diferencias entre cadena C++ == y comparar()?
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.
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!
std::string::compare() devuelve un int
:
- igual a cero si
s
yt
son iguales, - menor que cero si
s
es menor quet
, - mayor que cero si
s
es mayor quet
.
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 .
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).
compare
tiene sobrecargas para comparar subcadenas. Si está comparando cadenas completas, debería usar ==
operador (y si llama compare
o no es prácticamente irrelevante).