Acabo de leer algunas recomendaciones sobre el uso de
std::string s = get_string();
std::string t = another_string();
if( !s.compare(t) )
{
en lugar de
if( s == t )
{
Casi siempre uso la última porque estoy acostumbrado a ella y me parece 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 debería favorecerse una forma a la otra?
Estoy considerando sólo los casos en los que necesito saber si una cadena es el mismo valor que otra cadena.
Esto es lo que el estándar tiene que decir sobre "operador".
21.4.8.2 operador==**
...y la de los demás;
...y que no se puede hacer nada más...
...y la de los demás;
template<class charT, class traits, class Allocator..;
...de la clase..;
bool operator==(const basic_string<charT,traits,Allocator
lhs,
...y la de los demás;
const basic_string<charT,traits,Allocator&&
rhs) noexcepto;
`...
......
......
...y la de los demás;
Regresa:
lhs.compare(rhs) == 0.
Parece que hay'¡no hay mucha diferencia!
std::string::compare() devuelve un int
:
s
y t
son iguales,s
es menor que t
,s
es mayor que t
.Si quieres que tu primer fragmento de código sea equivalente al segundo, en realidad debería decir
if (!s.compare(t)) {
// 's' and 't' are equal.
}
El operador de igualdad sólo comprueba la igualdad (de ahí su nombre) y devuelve un bool
.
Para profundizar en los casos de uso, compare()
puede ser útil si te interesa saber cómo se relacionan las dos cadenas (menor o mayor) cuando resultan ser diferentes. PlasmaHH menciona acertadamente los árboles, y también podría ser, digamos, un algoritmo de inserción de cadenas que pretende mantener el contenedor ordenado, un algoritmo de búsqueda dicotómica para el mencionado contenedor, etc.
EDIT: Como señala Steve Jessop en los comentarios, compare()
es más útil para los algoritmos de ordenación rápida y búsqueda binaria. Las ordenaciones naturales y las búsquedas dicotómicas pueden implementarse sólo con std::less.
Internamente, la cadena::operador==() está usando la cadena::compare(). Por favor, consulte: [CPlusPlus - Cadena::Operador==()][1]
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, la cadena::compare() es ligeramente más rápida que la cadena::operador==(). Sin embargo, si compilas y ejecutas tu código en un entorno de liberación, ambos son más o menos lo mismo.
Para tu información, ejecuté 1.000.000 de iteraciones para llegar a esa conclusión.
Para probar por qué en el entorno de depuración la cadena::compare es más rápida, fui al ensamblador y aquí está el código:
DEBUG BUILD
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)
cuerda::compara()
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 la cadena::operator==(), tiene que realizar operaciones extra (add esp, 8 and movzx edx,al)
LIBERAR 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)
cuerda::compara()
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 ensamblados 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 al desarrollador decidir cuál es el preferido ya que ambos logran el mismo resultado (especialmente cuando se trata de una construcción de lanzamiento).
[1]: http://www.cplusplus.com/reference/string/string/operators/
Si sólo quieres comprobar la igualdad de la cadena, usa el operador ==. Determinar si dos cadenas son iguales es más sencillo que encontrar un orden (que es lo que da compare()), por lo que puede ser mejor en cuanto a rendimiento en su caso utilizar el operador de igualdad.
Respuesta más larga: La API proporciona un método para comprobar la igualdad de las cadenas y un método para comprobar 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, puede probar ambos métodos y encontrar el más rápido.
Una cosa que no se cubre aquí es que depende de si comparamos cadena con cadena de c, cadena de c con cadena o cadena con cadena.
Una diferencia importante es que para comparar dos cuerdas se comprueba la igualdad de tamaño 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 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; }
Supongamos que consideremos dos cuerdas s y t. Dales algunos valores. Cuando los comparas usando (s==t) devuelve un valor booleano(verdadero o falso , 1 o 0). Pero cuando comparas usando s.compare(t) , la expresión devuelve un valor (i) 0 - si s y t son iguales ii) <0 - ya sea si el valor del primer carácter no coincidente en s es menor que el de t o la longitud de s es menor que la de t. iii) <0 - bien si el valor del primer carácter no emparejado en t es inferior al de s o la longitud de t es inferior a la de s.
En el depurador de Visual Studio 2012, sólo lo siguiente funciona correctamente cuando se comprueba si una cadena está vacía o no:
strcmp(somestring.c_str(),"")==0
...volver a la realidad.
somestring.compare("")
retorno 1, y
somestring==""
...regresa: no hay operador "==" coincide con estos operandos.
somestring.c_str()==""
...regresa: Se ha producido un error no especificado.