ความแตกต่างระหว่างสตริง C ++ == และเปรียบเทียบ ()?


363

ฉันเพิ่งอ่านคำแนะนำเกี่ยวกับการใช้

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

if( !s.compare(t) ) 
{

แทน

if( s == t )
{

ฉันเกือบจะใช้อันสุดท้ายเสมอเพราะฉันชินแล้วและรู้สึกเป็นธรรมชาติอ่านง่ายขึ้น ฉันไม่รู้ด้วยซ้ำว่ามีฟังก์ชั่นการเปรียบเทียบแยกต่างหาก เพื่อให้แม่นยำยิ่งขึ้นฉันคิดว่า == จะเรียกการเปรียบเทียบ ()

อะไรคือความแตกต่าง? ในบริบทใดที่ควรได้รับการสนับสนุนในอีกทางหนึ่ง?

ฉันกำลังพิจารณาเฉพาะกรณีที่ฉันต้องรู้ว่าสตริงเป็นค่าเดียวกันกับสตริงอื่น


5
คนแรกจะกลับมาจริงที่ที่คนหลังกลับเท็จและในทางกลับกัน
Viktor Sehr

56
คนแรกอ่านแทบจะไม่ได้ในขณะที่คนหลังอ่านและเข้าใจได้ง่าย
Matthieu M.

3
ฉันใช้ฟังก์ชั่น "เปรียบเทียบ" เช่นนี้: if(x.compare(y) == 0)<- เท่ากับเครื่องหมายมันเท่ากัน IMO ที่ใช้!เพียงทำหน้าที่ในการทำให้โค้ดอ่านไม่ได้
R. Martinho Fernandes

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
หมายเหตุถึงผู้อ่าน: โปรดอ่านคำตอบของFrédéric Hamidiสำหรับรายละเอียดเกี่ยวกับเรื่องนี้เนื่องจากมีความแตกต่างที่เกี่ยวข้อง แม้ว่าฉันดีใจที่ Bo Persson แสดงให้เห็นว่าการทดสอบทั้งสองจะกลับมาเป็นค่าเดิมแน่นอน !s.compare(t)และs == tจะกลับมามีค่าเท่ากัน แต่ฟังก์ชั่นเปรียบเทียบให้ข้อมูลมากกว่าs == tและs == tสามารถอ่านได้มากขึ้นเมื่อคุณไม่สนใจวิธีการเงื่อนไขที่แตกต่างกัน แต่ถ้าพวกเขาแตกต่าง
cdgraham

143

std :: string :: compare ()ส่งคืน an int:

  • เท่ากับศูนย์ถ้าsและtเท่ากับ
  • น้อยกว่าศูนย์ถ้าsมีค่าน้อยกว่าt,
  • มากกว่าศูนย์ถ้ามีค่ามากกว่าst

หากคุณต้องการให้ข้อมูลโค้ดแรกของคุณเทียบเท่ากับข้อมูลโค้ดที่สองควรอ่านจริง:

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

ผู้ประกอบการเท่าเทียมกันเพียงการทดสอบเพื่อความเท่าเทียมกัน (เพราะฉะนั้นชื่อ) boolและผลตอบแทน

ในการอธิบายรายละเอียดเกี่ยวกับกรณีการใช้งานcompare()จะมีประโยชน์หากคุณสนใจว่าทั้งสองสายเกี่ยวข้องกันอย่างไร (น้อยกว่าหรือมากกว่า) เมื่อเกิดความแตกต่าง PlasmaHH กล่าวถึงต้นไม้อย่างถูกต้องและอาจกล่าวได้ว่าเป็นอัลกอริธึมการแทรกสตริงที่มีจุดมุ่งหมายเพื่อให้ภาชนะเรียงลำดับอัลกอริทึมการค้นหาแบบแบ่งขั้วสำหรับคอนเทนเนอร์ดังกล่าวและอื่น ๆ

แก้ไข:ตามที่สตีฟเจสซอพชี้ให้เห็นในความคิดเห็นcompare()มีประโยชน์มากที่สุดสำหรับอัลกอริทึมการเรียงลำดับอย่างรวดเร็วและค้นหา การเรียงลำดับตามธรรมชาติและการค้นหาแบบแบ่งขั้วสามารถนำไปใช้ได้ด้วยstd :: lessเท่านั้น


โปรดทราบว่าพฤติกรรมนี้มักจะมีประโยชน์เมื่อต้องรับมือกับต้นไม้หรือสิ่งมีชีวิตที่เหมือนต้นไม้
PlasmaHH

อันที่จริงก็คือผมเป็นเพียงการชี้ให้เห็นความแตกต่างระหว่างวิธีการและผู้ประกอบการเท่าเทียมกัน :)
Frédéric Hamidi

"ในบริบทใดที่ควรได้รับการสนับสนุนทางหนึ่ง? แค่ทำให้ฉันคิดว่า OP ไม่สามารถนึกถึงกรณีใช้ที่เป็นไปได้สำหรับการเปรียบเทียบ ()
PlasmaHH

2
"ถ้าคุณสนใจว่าทั้งสองสายเกี่ยวข้องกันอย่างไร" - ถึงแม้ว่าสำนวน C ++ สำหรับสิ่งนี้คือการใช้คำสั่งที่อ่อนแออย่างเข้มงวด (เช่นstd::lessซึ่งเป็นคำสั่งทั้งหมดในกรณีนี้) มากกว่าตัวเปรียบเทียบสามทาง . compare()สำหรับการดำเนินงานในรูปแบบstd::qsortและstd::bsearchเมื่อเทียบกับผู้ที่อยู่ในรูปแบบและstd:sort std::lower_bound
Steve Jessop

30

compareมีภาระเกินสำหรับการเปรียบเทียบสตริงย่อย หากคุณกำลังเปรียบเทียบสตริงทั้งหมดคุณควรใช้==โอเปอเรเตอร์ (และไม่ว่าจะเป็นการโทรcompareหรือไม่นั้นก็ไม่เกี่ยวข้องเลย)


30

ภายในใช้string::operator==() string::compare()โปรดอ้างอิงถึง: CPlusPlus -string::operator==()

ผมเขียนโปรแกรมขนาดเล็กเพื่อเปรียบเทียบประสิทธิภาพการทำงานและเห็นได้ชัดถ้าคุณรวบรวมและเรียกใช้รหัสของคุณในสภาพแวดล้อมการแก้ปัญหาจะเร็วกว่าเล็กน้อยstring::compare() string::operator==()อย่างไรก็ตามถ้าคุณคอมไพล์และรันโค้ดในสภาวะแวดล้อม Release ทั้งคู่ก็เหมือนกัน

FYI ฉันวิ่ง 1,000,000 ซ้ำเพื่อหาข้อสรุปดังกล่าว

เพื่อพิสูจน์ว่าทำไมในสภาพแวดล้อมการแก้ปัญหาสตริง :: การเปรียบเทียบเร็วขึ้นฉันไปที่การชุมนุมและนี่คือรหัส:

สร้างข้อบกพร่อง

สตริง :: ประกอบ == ()

        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

ฉันไม่ใช่ ... พวกมันเป็นสิ่งเดียวกัน ไม่มีความแตกต่าง
Wagner Patriota

1
@xtofl จากตัวอย่างของ Tony รหัสที่สร้างนั้นเหมือนกันใน build build พวกเขาต่างกันใน debug builds
JulianHarty

6

compare()เทียบเท่ากับ strcmp () ==เป็นการตรวจสอบความเสมอภาคอย่างง่าย compare()จึงส่งกลับint, ==เป็นแบบบูล


5

compare()จะส่งกลับfalse(ดี0) ถ้าสตริงเท่ากัน

ดังนั้นอย่าเอามาแลกเปลี่ยนกันเบา ๆ

ใช้วิธีใดก็ตามที่ทำให้โค้ดอ่านง่ายขึ้น


3

หากคุณต้องการตรวจสอบความเท่าเทียมกันของสตริงให้ใช้ตัวดำเนินการ == การพิจารณาว่าสองสตริงเท่ากันนั้นง่ายกว่าการค้นหาการจัดลำดับ (ซึ่งเป็นสิ่งที่เปรียบเทียบ () ให้) ดังนั้นจึงควรใช้ประสิทธิภาพดีกว่าในกรณีของคุณเพื่อใช้ตัวดำเนินการความเท่าเทียมกัน

คำตอบที่ยาวกว่า: API มีวิธีการตรวจสอบความเท่าเทียมกันของสตริงและวิธีตรวจสอบการสั่งซื้อสตริง คุณต้องการความเท่าเทียมกันของสตริงดังนั้นให้ใช้ตัวดำเนินการความเท่าเทียมกัน (เพื่อให้ความคาดหวังของคุณและของผู้จัดทำไลบรารีปรับแนว) หากประสิทธิภาพมีความสำคัญคุณอาจต้องการทดสอบทั้งสองวิธีและหาวิธีที่เร็วที่สุด


2

สมมติว่าพิจารณาสองสตริง s และ t
ให้คุณค่ากับพวกเขาบ้าง
เมื่อคุณเปรียบเทียบพวกเขาโดยใช้(s == t)มันจะคืนค่าบูลีน (จริงหรือเท็จ, 1 หรือ 0)
แต่เมื่อคุณเปรียบเทียบโดยใช้s.compare (t)นิพจน์จะส่งกลับค่า
(i) 0 - ถ้า s และ t เท่ากับ
(ii) <0 - อย่างใดอย่างหนึ่งหากค่าของอักขระที่ไม่ตรงกันในตัวแรกนั้นน้อยกว่า t หรือความยาวของ s น้อยกว่าของ t
(iii) > 0 - อย่างใดอย่างหนึ่งหากค่าของอักขระที่ไม่ตรงกันใน t มีค่าน้อยกว่า s หรือความยาวของ t น้อยกว่า s


1

สิ่งหนึ่งที่ไม่ได้กล่าวถึงในที่นี้คือมันขึ้นอยู่กับว่าเราเปรียบเทียบสตริงกับสตริง 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 และค้นหาโอเปอเรเตอร์ == บนระบบปฏิบัติการของคุณ รหัสไม่ใช่ของฉันเป็นของมาตรฐานความจริงที่ว่าการตรวจสอบขนาดคือสิ่งที่ขาดหายไปในเธรดนี้ ฉันยังเห็นว่าผู้คนจำนวนมากเห็นด้วยกับข้อมูลที่ไม่ถูกต้องซึ่งท้าทายยูทิลิตี้ของ Stack Overflow
Dragos
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.