Différences entre la chaîne C ++ == et compare ()?

363

Je viens de lire quelques recommandations sur l'utilisation

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

if( !s.compare(t) ) 
{

au lieu de

if( s == t )
{

J'utilise presque toujours le dernier parce que j'y suis habitué et il semble naturel, plus lisible. Je ne savais même pas qu'il y avait une fonction de comparaison distincte. Pour être plus précis, je pensais que == appellerait compare ().

Quelles sont les différences? Dans quels contextes faut-il privilégier une voie à l'autre?

Je ne considère que les cas où j'ai besoin de savoir si une chaîne a la même valeur qu'une autre chaîne.

Klaim
la source
5
Le premier retourne vrai où le dernier retourne faux, et vice versa.
Viktor Sehr
56
Le premier est à peine lisible tandis que le second est facile à lire et à comprendre.
Matthieu M.
3
J'utilise des fonctions "comparer" comme ceci: if(x.compare(y) == 0)<- signe égal, c'est égal. L'utilisation de l'OMI !ne sert qu'à rendre le code illisible.
R. Martinho Fernandes
1
Il convient de noter que == ne fonctionnera pas pour vous dans tous les cas. la chaîne surcharge l'opérateur pour effectuer une comparaison, donc == équivaut à appeler une comparaison. Alternativement, si vous essayez ceci sur des objets qui ne surchargent pas l'opérateur ==, vous comparerez leur adresse en mémoire, et non leurs composants internes. Appeler compare est plus «sûr». Dans le cas de l'utilisation de std :: string, tout va bien.
DCurro
Une différence: comparerenvoyer -1si sest inférieur à tet +1si sest supérieur à tpendant le ==retour true/false. Les entiers non nuls sont trueet 0sont false.
GyuHyeon Choi

Réponses:

450

Voilà ce que la norme a à dire operator==

21.4.8.2 opérateur ==

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

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

Il semble qu'il n'y ait pas beaucoup de différence!

Bo Persson
la source
5
Note aux lecteurs: Veuillez lire la réponse de Frédéric Hamidi pour plus de détails sur la question car il existe des différences pertinentes. Bien que je suis content que Bo Persson montre que les deux tests retourneront certainement la même valeur. !s.compare(t)et s == trenverra la même valeur, mais la fonction de comparaison fournit plus d'informations que s == t, et s == test plus lisible lorsque vous ne vous souciez pas de la façon dont les chaînes diffèrent, mais uniquement si elles diffèrent.
cdgraham
143

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

  • égal à zéro si set tsont égaux,
  • inférieur à zéro si sest inférieur à t,
  • supérieur à zéro si sest supérieur à t.

Si vous voulez que votre premier extrait de code soit équivalent au second, il devrait en fait se lire:

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

L'opérateur d'égalité teste uniquement l'égalité (d'où son nom) et renvoie a bool.

Pour élaborer sur les cas d'utilisation, compare()peut être utile si vous êtes intéressé par la façon dont les deux chaînes sont liées l'une à l'autre (moins ou plus) quand elles se trouvent être différentes. PlasmaHH mentionne à juste titre les arbres, et il pourrait également s'agir, par exemple, d'un algorithme d'insertion de chaîne qui vise à conserver le conteneur trié, d'un algorithme de recherche dichotomique pour le conteneur susmentionné, etc.

EDIT: Comme le souligne Steve Jessop dans les commentaires, compare()est le plus utile pour les algorithmes de tri rapide et de recherche binaire. Les tris naturels et les recherches dichotomiques peuvent être implémentés avec seulement std :: less .

Frédéric Hamidi
la source
notez que ce comportement est souvent utile lorsqu'il s'agit d'arbres ou de créatures arborescentes.
PlasmaHH
En effet, je ne faisais que signaler les différences entre la méthode et l'opérateur d'égalité :)
Frédéric Hamidi
"Dans quels contextes une voie devrait-elle être privilégiée à l'autre?" me fait juste penser que l'OP ne peut pas penser à des cas d'utilisation possibles pour compare ().
PlasmaHH
2
"si vous êtes intéressé par la façon dont les deux chaînes sont liées" - bien que le C ++ idiomatique pour cela consiste à utiliser un ordre faible strict (comme std::less, qui est également un ordre total dans ce cas) plutôt qu'un comparateur à trois voies . compare()est pour les opérations modélisées sur std::qsortet std::bsearch, contrairement à celles modélisées sur std:sortet std::lower_bound.
Steve Jessop
30

comparea des surcharges pour comparer les sous-chaînes. Si vous comparez des chaînes entières, vous devez simplement utiliser l' ==opérateur (et qu'il appelle compareou non est à peu près hors de propos).

Cat Plus Plus
la source
30

En interne, string::operator==()utilise string::compare(). Veuillez vous référer à: CPlusPlus -string::operator==()

J'ai écrit une petite application pour comparer les performances, et apparemment, si vous compilez et exécutez votre code sur l'environnement de débogage, il string::compare()est légèrement plus rapide que string::operator==(). Cependant, si vous compilez et exécutez votre code dans l'environnement Release, les deux sont à peu près les mêmes.

Pour info, j'ai exécuté 1 000 000 d'itérations afin de parvenir à une telle conclusion.

Afin de prouver pourquoi dans l'environnement de débogage la chaîne :: compare est plus rapide, je suis allé à l'assembly et voici le code:

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)

Vous pouvez voir que dans string :: operator == (), il doit effectuer des opérations supplémentaires (ajouter esp, 8 et movzx edx, al)

RELEASE BUILD

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)

Les deux codes d'assemblage sont très similaires car le compilateur effectue l'optimisation.

Enfin, à mon avis, le gain de performances est négligeable, donc je laisse vraiment le soin au développeur de décider lequel est le préféré car les deux atteignent le même résultat (surtout quand il s'agit de la version build).

Tony Mulia
la source
10
'très similaire' ... Je ne vois aucune différence, n'est-ce pas?
xtofl
moi non plus ... c'est la même chose. il n'y a pas de différence
Wagner Patriota
1
@xtofl de l'exemple de Tony, les codes générés sont identiques dans la version finale, ils sont différents dans les versions de débogage.
JulianHarty
6

compare()est équivalent à strcmp (). ==est une simple vérification d'égalité. compare()renvoie donc un int, ==est un booléen.

ckruse
la source
5

compare()retournera false(enfin 0) si les chaînes sont égales.

Alors ne prenez pas à la légère l'échange l'un pour l'autre.

Utilisez celui qui rend le code plus lisible.

Luchian Grigore
la source
3

Si vous souhaitez simplement vérifier l'égalité des chaînes, utilisez l'opérateur ==. Déterminer si deux chaînes sont égales est plus simple que de trouver un ordre (ce que donne compare (), donc il pourrait être préférable, dans votre cas, d'utiliser les performances de l'opérateur d'égalité.

Réponse plus longue: l'API fournit une méthode pour vérifier l'égalité des chaînes et une méthode pour vérifier l'ordre des chaînes. Vous voulez l'égalité des chaînes, utilisez donc l'opérateur d'égalité (afin que vos attentes et celles des implémenteurs de bibliothèque s'alignent.) Si les performances sont importantes, vous pouvez tester les deux méthodes et trouver la plus rapide.

RobH
la source
2

Supposons que nous considérons deux chaînes s et t.
Donnez-leur des valeurs.
Lorsque vous les comparez à l'aide de (s == t), il renvoie une valeur booléenne (vrai ou faux, 1 ou 0).
Mais lorsque vous comparez à l'aide de s.compare (t) , l'expression renvoie une valeur
(i) 0 - si s et t sont égaux
(ii) <0 - soit si la valeur du premier caractère sans correspondance dans s est inférieure à celle de t ou la longueur de s est inférieure à celle de t.
(iii) > 0 - soit si la valeur du premier caractère sans correspondance dans t est inférieure à celle de s ou la longueur de t est inférieure à celle de s.

narutoUzumaki21
la source
1

Une chose qui n'est pas couverte ici est que cela dépend si nous comparons chaîne à chaîne c, chaîne c à chaîne ou chaîne à chaîne.

Une différence majeure est que pour comparer deux chaînes, l'égalité de taille est vérifiée avant de faire la comparaison et cela rend l'opérateur == plus rapide qu'une comparaison.

voici la comparaison telle que je la vois sur 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
la source
le code est formaté et affiché formaté dans l'éditeur. L'affichage s'est trompé. ouvrez basic_string.h et recherchez l'opérateur == sur votre système d'exploitation. Le code n'est pas le mien est standard, le fait que la vérification de la taille soit ce qui manque dans ce fil. Je constate également que de nombreuses personnes sont d'accord avec des informations incorrectes qui défient l'utilité de Stack Overflow.
Dragos