Различия между строкой C ++ == и сравнением ()?

363

Я просто прочитал несколько рекомендаций по использованию

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

if( !s.compare(t) ) 
{

вместо

if( s == t )
{

Я почти всегда использую последний, потому что привык к нему, и он кажется естественным, более читабельным. Я даже не знал, что была отдельная функция сравнения. Чтобы быть более точным, я думал, что == вызовет Compare ().

В чем различия? В каком контексте один путь следует отдавать предпочтение другому?

Я рассматриваю только те случаи, когда мне нужно знать, совпадает ли строка с другой строкой.

Klaim
источник
5
Первый вернет true, где последний вернет false, и наоборот.
Виктор Сер
56
Первый почти не читается, а второй легко читается и понимается.
Матье М.
3
Я использую функции «сравнения» следующим образом: if(x.compare(y) == 0)<- знак равенства, он равен. Использование IMO !служит только для того, чтобы сделать код нечитаемым.
Р. Мартиньо Фернандес
1
Следует отметить, что == не будет работать для вас в каждом случае. Строка перегружает оператор для выполнения сравнения, поэтому == - это то же самое, что вызов сравнения. В качестве альтернативы, если вы попробуете это на объектах, которые не перегружают оператор ==, вы будете сравнивать их адреса в памяти, а не их внутренние компоненты. Сравнение вызовов более «безопасно». В случае использования std :: string у вас все хорошо.
DCurro
Одно отличие: compareвозврат, -1если sменьше, чем, tи +1если sбольше, чем tво время ==возврата true/false. Ненулевые целые числа есть trueи 0есть false.
GyuHyeon Чой

Ответы:

450

Это то, что стандарт должен сказать о operator==

21.4.8.2 оператор ==

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

Возвращает: lhs.compare (rhs) == 0.

Похоже, нет большой разницы!

Бо Перссон
источник
5
Примечание для читателей: Пожалуйста, прочитайте ответ Фредерика Хамиди для деталей по этому вопросу, потому что есть соответствующие различия. Хотя я рад, что Бо Перссон показывает, что два теста определенно вернут одно и то же значение. !s.compare(t)и s == tвернет то же значение, но функция сравнения предоставляет больше информации, чем s == t, и s == tболее читабельна, когда вам все равно, как отличаются строки, но только если они отличаются.
cdgraham
143

std :: string :: compare () возвращает int:

  • равно нулю, если sиt равны,
  • меньше нуля, если sменьше чемt ,
  • больше нуля, если sбольше чем t.

Если вы хотите, чтобы ваш первый фрагмент кода был эквивалентен второму, он должен выглядеть так:

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

Оператор равенства проверяет только равенство (отсюда и его имя) и возвращает bool .

Разобраться в вариантах использования compare()может быть полезно, если вас интересует, как две строки связаны друг с другом (меньше или больше), когда они разные. PlasmaHH справедливо упоминает деревья, и это может быть, скажем, алгоритм вставки строк, который стремится сохранить сортировку контейнера, алгоритм дихотомического поиска для вышеупомянутого контейнера и так далее.

РЕДАКТИРОВАТЬ: Как отмечает Стив Джессоп в комментариях, compare()наиболее полезно для быстрой сортировки и алгоритмов двоичного поиска. Естественные сортировки и дихотомический поиск могут быть реализованы только с помощью std :: less .

Фредерик Хамиди
источник
обратите внимание, что это поведение часто полезно при работе с деревьями или древовидными существами.
PlasmaHH
Действительно, я только указывал на различия между методом и оператором равенства :)
Фредерик Хамиди
«В каком контексте один путь следует отдавать предпочтение другому?» просто заставляет меня думать, что ОП не может придумать возможные варианты использования для сравнения ().
PlasmaHH
2
«если вам интересно, как эти две строки связаны друг с другом» - хотя идиоматический C ++ для этого должен использовать строгий слабый порядок (например std::less, который также является полным порядком в данном случае), а не трехсторонний компаратор , compare()для операций, смоделированных на std::qsortи std::bsearch, в отличие от тех, на которых смоделированы std:sortи std::lower_bound.
Стив Джессоп
30

compareимеет перегрузки для сравнения подстрок. Если вы сравниваете целые строки, вы должны просто использовать ==оператор (и неважно, вызывает он это compareили нет).

Cat Plus Plus
источник
30

Внутренне string::operator==()использует string::compare(). Пожалуйста, обратитесь к: CPlusPlus -string::operator==()

Я написал небольшое приложение для сравнения производительности, и, очевидно, если вы компилируете и запускаете свой код в среде отладки, string::compare()это немного быстрее, чем string::operator==(). Однако, если вы компилируете и запускаете свой код в среде Release, оба они в значительной степени одинаковы.

К вашему сведению, я провел 1 000 000 итераций, чтобы прийти к такому выводу.

Для того чтобы доказать, почему в среде отладки строка :: сравнивается быстрее, я пошел в сборку и вот код:

DEBUG BUILD

строка :: оператор == ()

        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)  

строка :: сравнить ()

            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)

Вы можете видеть, что в string :: operator == () он должен выполнять дополнительные операции (добавить esp, 8 и movzx edx, al)

РЕЛИЗ СТРОЙ

строка :: оператор == ()

        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)  

строка :: сравнить ()

            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)

Оба ассемблерных кода очень похожи, так как компилятор выполняет оптимизацию.

Наконец, по моему мнению, прирост производительности незначителен, поэтому я бы действительно оставил разработчику право решать, какой из них предпочтительнее, поскольку оба достигают одного и того же результата (особенно когда это сборка релиза).

Тони Мулиа
источник
10
«очень похоже» ... я не вижу разницы, а вы?
xtofl
я тоже ... они одно и то же. нет никакой разницы
Вагнер Патриота
1
@xtofl из примера Тони, сгенерированные коды идентичны в сборке релиза, они отличаются в сборках отладки.
JulianHarty
6

compare()эквивалентно strcmp (). ==простая проверка на равенство compare()поэтому возвращает int, ==является логическим.

ckruse
источник
5

compare()вернется false(ну,0 ), если строки равны.

Так что не смей обменивать одно на другое.

Используйте то, что делает код более читабельным.

Лучиан Григоре
источник
3

Если вы просто хотите проверить равенство строк, используйте оператор ==. Определить, равны ли две строки, проще, чем найти порядок (который дает сравнение (), так что он может в вашем случае быть лучше использовать оператор равенства.

Более длинный ответ: API предоставляет метод проверки на равенство строк и метод проверки порядка строк. Вам нужно равенство строк, поэтому используйте оператор равенства (чтобы ваши ожидания и ожидания разработчиков библиотек совпали.) Если производительность важна, вы можете протестировать оба метода и найти самый быстрый.

RobH
источник
2

Предположим, рассмотрим две строки s и t.
Дайте им некоторые значения.
Когда вы сравниваете их, используя (s == t), он возвращает логическое значение (true или false, 1 или 0).
Но когда вы сравниваете, используя s.compare (t) , выражение возвращает значение
(i) 0 - если s и t равны
(ii) <0 - либо если значение первого несопоставленного символа в s меньше, чем значение t или длина s меньше, чем у t.
(iii) > 0 - либо если значение первого несопоставленного символа в t меньше значения s, либо длина t меньше значения s.

narutoUzumaki21
источник
1

Одна вещь, которая здесь не рассматривается, это то, что это зависит от того, сравниваем ли мы строку со строкой c, c строкой со строкой или строкой со строкой.

Основное отличие состоит в том, что для сравнения двух строк проверяется равенство размеров перед выполнением сравнения, и это делает оператор == быстрее, чем сравнение.

вот сравнение, как я вижу это на 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
источник
Код отформатирован и показан отформатирован в редакторе. Дисплей ошибся. откройте basic_string.h и найдите operator == в вашей ОС. Код не мой является стандартным, тот факт, что проверка размера является то, что отсутствует в этой теме. Я также вижу, что многие люди согласны с неверной информацией, которая не поддается утилизации Stack Overflow.
Драгос