Diferenças entre C ++ string == e compare ()?

363

Acabei de ler algumas recomendações sobre o uso

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

if( !s.compare(t) ) 
{

ao invés de

if( s == t )
{

Estou quase sempre usando o último porque estou acostumado a isso e parece natural, mais legível. Eu nem sabia que havia uma função de comparação separada. Para ser mais preciso, pensei que == chamaria compare ().

Quais são as diferenças? Em quais contextos uma maneira deve ser favorecida à outra?

Estou considerando apenas os casos em que preciso saber se uma string tem o mesmo valor que outra string.

Klaim
fonte
5
O primeiro retornará verdadeiro, enquanto o último retornará falso, e vice-versa.
Viktor Sehr
56
O primeiro é pouco legível, enquanto o último é facilmente lido e compreendido.
Matthieu M.
3
Eu uso "compare" funções como esta: if(x.compare(y) == 0)<- sinal de igual, é igual. O IMO usando !serve apenas para tornar o código ilegível.
R. Martinho Fernandes
11
Note-se que == não funcionará para você em todos os casos. A string sobrecarrega o operador para realizar uma comparação, portanto == é o mesmo que chamar uma comparação. Como alternativa, se você tentar fazer isso em objetos que não sobrecarregam o operador ==, você estará comparando o endereço na memória e não os componentes internos. Ligar para comparar é mais "seguro". No caso de usar std :: string, você está bem.
precisa saber é o seguinte
Uma diferença: comparereturn -1se sfor menor que te +1se sfor maior que twhile ==return true/false. Inteiros diferentes de zero são truee 0são false.
GyuHyeon Choi 20/01

Respostas:

450

É isso que o padrão tem a dizer sobre operator==

21.4.8.2 operator ==

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

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

Parece que não há muita diferença!

Bo Persson
fonte
5
Nota aos leitores: Leia a resposta de Frédéric Hamidi para obter detalhes sobre o assunto, porque existem diferenças relevantes. Embora eu esteja feliz por Bo Persson mostrar que os dois testes definitivamente retornarão o mesmo valor. !s.compare(t)e s == tretornará o mesmo valor, mas a função comparar fornece mais informações do que s == te s == té mais legível quando você não se importa com a diferença entre as seqüências, mas apenas se elas diferem.
cdgraham
143

std :: string :: compare () retorna um int:

  • igual a zero se se tsão iguais,
  • menor que zero se sfor menor que t,
  • maior que zero se sfor maior que t.

Se você deseja que seu primeiro trecho de código seja equivalente ao segundo, ele deve realmente ler:

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

O operador de igualdade testa apenas a igualdade (daí seu nome) e retorna a bool.

Para elaborar os casos de uso, compare()pode ser útil se você estiver interessado em saber como as duas seqüências se relacionam (menos ou maior) quando elas são diferentes. O PlasmaHH menciona com razão as árvores e também pode ser, por exemplo, um algoritmo de inserção de string que visa manter o contêiner classificado, um algoritmo de pesquisa dicotômica para o contêiner mencionado e assim por diante.

EDIT: Como Steve Jessop aponta nos comentários, compare()é mais útil para ordenação rápida e algoritmos de pesquisa binária. Classificações naturais e pesquisas dicotômicas podem ser implementadas apenas com std :: less .

Frédéric Hamidi
fonte
observe que esse comportamento geralmente é útil ao lidar com árvores ou criaturas semelhantes a árvores.
PlasmaHH
Na verdade, é, só foi apontar as diferenças entre o método e o operador de igualdade :)
Frédéric Hamidi
"Em quais contextos uma maneira deve ser favorecida à outra?" apenas me faz pensar que o OP não pode pensar em possíveis casos de uso para compare ().
PlasmaHH
2
"se você estiver interessado em como as duas seqüências se relacionam" - embora o C ++ idiomático para isso seja usar uma ordem fraca estrita (como std::less, que também é uma ordem total nesse caso), em vez de um comparador de três vias . compare()é para operações modeladas em std::qsorte std::bsearch, em oposição às modeladas em std:sorte std::lower_bound.
Steve Jessop
30

comparepossui sobrecargas para comparar substrings. Se você estiver comparando cadeias inteiras, use o ==operador (e se chama compareou não, é praticamente irrelevante).

Cat Plus Plus
fonte
30

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

Eu escrevi um pequeno aplicativo para comparar o desempenho e, aparentemente, se você compilar e executar seu código no ambiente de depuração, string::compare()é um pouco mais rápido que string::operator==(). No entanto, se você compilar e executar seu código no ambiente Release, ambos serão praticamente iguais.

Para sua informação, executei 1.000.000 de iterações para chegar a essa conclusão.

Para provar por que, no ambiente de depuração, a string :: compare é mais rápida, fui ao assembly e aqui está o código:

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)

Você pode ver que em string :: operator == (), ele precisa executar operações extras (adicione esp, 8 e movzx edx, al)

CONSTRUÇÃO DE LANÇAMENTO

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)

Ambos os códigos de montagem são muito semelhantes, pois o compilador executa a otimização.

Finalmente, na minha opinião, o ganho de desempenho é insignificante, portanto, eu realmente deixaria para o desenvolvedor decidir qual é o preferido, pois ambos alcançam o mesmo resultado (especialmente quando é a versão lançada).

Tony Mulia
fonte
10
'muito parecido' ... não vejo diferença, entende?
Xtofl
eu também não ... eles são a mesma coisa. não há diferença
Wagner Patriota
11
@xtofl do exemplo de Tony, os códigos gerados são idênticos na versão de lançamento, são diferentes nas versões de depuração.
precisa saber é o seguinte
6

compare()é equivalente a strcmp (). ==é simples verificação de igualdade. compare()portanto retorna um int, ==é um booleano.

ckruse
fonte
5

compare()retornará false(bem 0) se as strings forem iguais.

Portanto, não pense em trocar um pelo outro de ânimo leve.

Use o que tornar o código mais legível.

Luchian Grigore
fonte
3

Se você quiser apenas verificar a igualdade das cadeias, use o operador ==. Determinar se duas seqüências são iguais é mais simples do que encontrar uma ordenação (que é o que compare () dá,) para que ele possa ser melhor em termos de performance no seu caso para usar o operador de igualdade.

Resposta mais longa: a API fornece um método para verificar a igualdade de cadeias e um método para verificar a ordem das cadeias. Você deseja igualdade de string, portanto, use o operador de igualdade (para que suas expectativas e as dos implementadores de bibliotecas se alinhem.) Se o desempenho for importante, você poderá testar os dois métodos e encontrar o mais rápido.

RobH
fonte
2

Suponha que considere duas cadeias s e t.
Dê a eles alguns valores.
Quando você os compara usando (s == t), ele retorna um valor booleano (verdadeiro ou falso, 1 ou 0).
Mas quando você compara usando s.compare (t) , a expressão retorna um valor
(i) 0 - se s e t forem iguais
(ii) <0 - se o valor do primeiro caractere não correspondido em s for menor que o valor de t ou o comprimento de s é menor que o de t.
(iii) > 0 - se o valor do primeiro caractere não correspondido em t for menor que o de s ou se o comprimento de t for menor que o de s.

narutoUzumaki21
fonte
1

Uma coisa que não é abordada aqui é que depende se compararmos string com c string, c string com string ou string com string.

Uma grande diferença é que, para comparar duas cadeias, a igualdade de tamanho é verificada antes de fazer a comparação e isso torna o operador == mais rápido que uma comparação.

aqui está a comparação que eu vejo no 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
fonte
O código é formatado e mostrado formatado no editor. O display entendeu errado. abra basic_string.he procure o operador == no seu sistema operacional. O código não é meu é padrão, o fato de que a verificação do tamanho é o que está faltando nesse segmento. Também vejo que muitas pessoas concordam com informações incorretas que desafiam o utilitário do Stack Overflow.
Dragos