Відмінності між рядком C ++ == та порівнянням ()?


363

Я просто прочитав деякі рекомендації щодо використання

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

if( !s.compare(t) ) 
{

замість

if( s == t )
{

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

Які відмінності? У якому контексті слід віддавати перевагу одному із способів іншого?

Я розглядаю лише випадки, коли мені потрібно знати, чи є рядок того ж значення, що й інший рядок.


5
Перший поверне істину там, де другий поверне помилкове, і навпаки.
Віктор Шер

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 Choi

Відповіді:


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.
}

Оператор рівності перевіряє лише рівність (звідси його назва) і повертає a bool.

Щоб детальніше compare()ознайомитись із випадками використання, може бути корисним, якщо вас цікавить, як два рядки співвідносяться одна з одною (меншою чи більшою), коли вони стають різними. PlasmaHH справедливо згадує дерева, і це може бути, скажімо, алгоритм вставки рядків, який спрямований на те, щоб сортувати контейнер, алгоритм дихотомічного пошуку для вищезазначеного контейнера тощо.

EDIT: Як в коментарях зазначає Стів Джессоп, compare()він найбільш корисний для алгоритмів швидкого сортування та двійкового пошуку. Природні сорти та дихотомічні пошуки можна реалізувати лише за допомогою std :: less .


зауважте, що така поведінка часто корисна при роботі з деревами або деревоподібними істотами.
ПлазмаHH

Дійсно, я лише вказував на відмінності між методом та оператором рівності :)
Фредерік Хаміді

"У якому контексті слід віддавати перевагу одному із способів іншого?" просто змушує мене думати, що ОП не може придумати можливі випадки використання для порівняння ().
ПлазмаHH

2
"якщо вас цікавить, як два рядки ставляться один до одного" - хоча ідіоматичний C ++ для цього полягає у використанні суворого слабкого порядку (наприклад std::less, що в цьому випадку також є загальним порядком), а не тристороннього порівняння . compare()призначений для операцій, що моделюються std::qsortта std::bsearch, на відміну від тих, що моделюються на std:sortта std::lower_bound.
Стів Джессоп

30

compareмає перевантаження для порівняння підрядків. Якщо ви порівнюєте цілі рядки, вам слід просто скористатися ==оператором (і те, чи викликає він це compareчи ні, в значній мірі не має значення).


30

Внутрішньо, string::operator==()використовується string::compare(). Будь ласка, зверніться до: CPlusPlus -string::operator==()

Я написав невеликий додаток для порівняння продуктивності, і, мабуть, якщо ви компілюєте і запускаєте свій код у середовищі налагодження, string::compare()це трохи швидше, ніж string::operator==(). Однак якщо ви компілюєте та запускаєте код у середовищі випуску, обидва майже однакові.

FYI, я здійснив 1 000 000 ітерацій, щоб прийти до такого висновку.

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

ДЕБУГОВА БУДОВА

рядок :: 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)  

рядок :: порівняти ()

            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)

ЗВ'ЯЗКОВА БУДОВА

рядок :: 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)  

рядок :: порівняти ()

            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()тому повертає an int, ==є булевим.


5

compare()повернеться false(добре, 0), якщо рядки рівні.

Тому не сприймайте обмін один за іншим легко.

Використовуйте те, що робить код більш читабельним.


3

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

Більш довга відповідь: API надає метод перевірки рівності рядків та метод перевірки впорядкування рядків. Вам потрібно рівність рядків, тому використовуйте оператор рівності (так, щоб ваші очікування та очікування виконавців бібліотеки вирівнювались.) Якщо продуктивність важлива, то ви можете перевірити обидва методи та знайти найшвидший.


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.


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; }

код відформатований і показаний відформатований у редакторі. Дисплей помилився. відкрийте basic_string.h і шукайте оператора == у вашій ОС. Код не мій є стандартним, той факт, що перевірка розміру - те, чого не вистачає в цій темі. Я також бачу, що багато людей погоджуються з невірною інформацією, яка не відповідає корисності переповнення стека.
Драгос
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.