Sự khác nhau giữa chuỗi C ++ == và so sánh ()?


363

Tôi chỉ đọc một số khuyến nghị về việc sử dụng

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

if( !s.compare(t) ) 
{

thay vì

if( s == t )
{

Tôi hầu như luôn sử dụng cái cuối cùng bởi vì tôi đã quen với nó và nó cảm thấy tự nhiên, dễ đọc hơn. Tôi thậm chí không biết rằng có một chức năng so sánh riêng biệt. Nói chính xác hơn, tôi nghĩ == sẽ gọi so sánh ().

Sự khác biệt là gì? Trong bối cảnh nào nên được ưu tiên cho cách khác?

Tôi chỉ xem xét các trường hợp tôi cần biết nếu một chuỗi có cùng giá trị với một chuỗi khác.


5
Cái đầu tiên sẽ trả về true trong khi cái sau trả về false và ngược lại.
Viktor Sehr

56
Cái đầu tiên hầu như không đọc được trong khi cái sau dễ đọc và dễ hiểu.
Matthieu M.

3
Tôi sử dụng các hàm "so sánh" như thế này: if(x.compare(y) == 0)<- dấu bằng, nó bằng nhau. IMO sử dụng !chỉ phục vụ để làm cho mã không thể đọc được.
R. Martinho Fernandes

1
Cần lưu ý rằng == sẽ không hiệu quả với bạn trong mọi trường hợp. chuỗi quá tải toán tử để thực hiện so sánh, vì vậy == giống như gọi một so sánh. Ngoài ra, nếu bạn thử điều này trên các đối tượng không quá tải toán tử ==, bạn sẽ so sánh địa chỉ của chúng trong bộ nhớ chứ không phải các thành phần bên trong của chúng. Gọi so sánh là "an toàn hơn". Trong trường hợp sử dụng std :: string, bạn vẫn ổn.
DCurro

Một sự khác biệt: comparetrở lại -1nếu sthấp hơn t+1nếu slớn hơn ttrong khi ==lợi nhuận true/false. Số nguyên khác không true0đang false.
GyuHyeon Choi

Câu trả lời:


450

Đây là những gì tiêu chuẩn đã nói về operator==

Toán tử 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;

Trả về: lhs.compare (rhs) == 0.

Có vẻ như không có nhiều sự khác biệt!


5
Lưu ý cho độc giả: Vui lòng đọc câu trả lời của Frédéric Hamidi để biết chi tiết về vấn đề này vì có những khác biệt có liên quan. Mặc dù tôi rất vui vì Bo Persson cho thấy hai bài kiểm tra chắc chắn sẽ trả về cùng một giá trị. !s.compare(t)s == tsẽ trả về cùng một giá trị, nhưng hàm so sánh cung cấp nhiều thông tin hơn s == ts == tdễ đọc hơn khi bạn không quan tâm các chuỗi khác nhau như thế nào nhưng chỉ khi chúng khác nhau.
cdgraham

143

std :: string :: so sánh () trả về một int:

  • bằng 0 nếu stbằng nhau,
  • nhỏ hơn không nếu snhỏ hơn t,
  • lớn hơn 0 nếu slớn hơn t.

Nếu bạn muốn đoạn mã đầu tiên của mình tương đương với đoạn mã thứ hai, thì nó thực sự nên đọc:

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

Toán tử đẳng thức chỉ kiểm tra sự bằng nhau (do đó tên của nó) và trả về a bool.

Để giải thích các trường hợp sử dụng, compare()có thể hữu ích nếu bạn quan tâm đến việc hai chuỗi liên quan đến nhau như thế nào (ít hơn hoặc lớn hơn) khi chúng xảy ra khác nhau. PlasmaHH đề cập chính xác đến cây, và cũng có thể là thuật toán chèn chuỗi nhằm giữ cho container được sắp xếp, thuật toán tìm kiếm nhị phân cho container đã nói ở trên, v.v.

EDIT: Như Steve Jessop đã chỉ ra trong các bình luận, compare()hữu ích nhất cho các thuật toán tìm kiếm nhị phân và tìm kiếm nhanh. Các loại tìm kiếm tự nhiên và phân đôi có thể được thực hiện chỉ với std :: less .


lưu ý rằng hành vi này thường hữu ích khi tiếp xúc với cây hoặc sinh vật giống cây.
PlasmaHH

Thật vậy, tôi chỉ chỉ ra sự khác biệt giữa phương thức và toán tử đẳng thức :)
Frédéric Hamidi

"Trong bối cảnh nào nên được ưu tiên cho cách khác?" chỉ khiến tôi nghĩ rằng OP không thể nghĩ ra các trường hợp sử dụng có thể để so sánh ().
PlasmaHH

2
"nếu bạn quan tâm đến việc hai chuỗi liên quan đến nhau như thế nào" - mặc dù C ++ thành ngữ cho việc này là sử dụng một thứ tự yếu nghiêm ngặt (như std::less, cũng là một tổng số trong trường hợp này) chứ không phải là một bộ so sánh ba chiều . compare()dành cho các hoạt động được mô hình hóa trên std::qsortstd::bsearch, trái ngược với các hoạt động được mô hình hóa trên std:sortstd::lower_bound.
Steve Jessop

30

comparecó quá tải để so sánh các chuỗi con. Nếu bạn đang so sánh toàn bộ chuỗi, bạn chỉ nên sử dụng ==toán tử (và liệu nó có gọi comparehay không là không liên quan).


30

Trong nội bộ, string::operator==()đang sử dụng string::compare(). Vui lòng tham khảo: CPlusPlus -string::operator==()

Tôi đã viết một ứng dụng nhỏ để so sánh hiệu suất và rõ ràng nếu bạn biên dịch và chạy mã của mình trên môi trường gỡ lỗi string::compare()thì nhanh hơn một chút string::operator==(). Tuy nhiên, nếu bạn biên dịch và chạy mã của mình trong môi trường Phát hành, cả hai đều khá giống nhau.

FYI, tôi đã chạy 1.000.000 lần lặp để đưa ra kết luận như vậy.

Để chứng minh tại sao trong môi trường gỡ lỗi, chuỗi :: so sánh nhanh hơn, tôi đã đi đến hội đồng và đây là đoạn mã:

XÂY DỰNG DEBUG

chuỗi :: toán tử == ()

        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)  

chuỗi :: so sánh ()

            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)

Bạn có thể thấy rằng trong chuỗi :: toán tử == (), nó phải thực hiện các hoạt động bổ sung (thêm đặc biệt, 8 và Movzx edx, al)

XÂY DỰNG

chuỗi :: toán tử == ()

        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)  

chuỗi :: so sánh ()

            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)

Cả hai mã lắp ráp rất giống như trình biên dịch thực hiện tối ưu hóa.

Cuối cùng, theo ý kiến ​​của tôi, mức tăng hiệu suất là không đáng kể, do đó tôi thực sự sẽ để nó cho nhà phát triển quyết định xem cái nào là ưu tiên nhất vì cả hai đều đạt được kết quả như nhau (đặc biệt là khi nó được phát hành bản dựng).


10
"Rất giống nhau" ... Tôi thấy không có gì khác biệt, phải không?
xtofl

tôi cũng vậy ... chúng giống nhau không có sự khác biệt
Wagner Patriota

1
@xtofl từ ví dụ của Tony, các mã được tạo giống hệt nhau trong bản dựng phát hành, chúng khác nhau trong các bản dựng gỡ lỗi.
JulianHarty

6

compare()tương đương với strcmp (). ==là kiểm tra bình đẳng đơn giản. compare()do đó trả về một int, ==là một boolean.


5

compare()sẽ trở lại false(tốt,0 ) nếu các chuỗi bằng nhau.

Vì vậy, đừng nhẹ nhàng trao đổi cái này với cái kia.

Sử dụng bất cứ điều gì làm cho mã dễ đọc hơn.


3

Nếu bạn chỉ muốn kiểm tra đẳng thức chuỗi, hãy sử dụng toán tử ==. Việc xác định xem hai chuỗi có bằng nhau hay không là đơn giản hơn so với việc tìm kiếm một thứ tự (đó là những gì so sánh () đưa ra,) để có thể sử dụng toán tử đẳng thức tốt hơn trong trường hợp của bạn.

Câu trả lời dài hơn: API cung cấp một phương thức để kiểm tra sự bằng nhau của chuỗi và một phương thức để kiểm tra thứ tự chuỗi. Bạn muốn bình đẳng chuỗi, vì vậy hãy sử dụng toán tử đẳng thức (sao cho kỳ vọng của bạn và của những người triển khai thư viện phù hợp.) Nếu hiệu suất là quan trọng thì bạn có thể muốn kiểm tra cả hai phương pháp và tìm ra phương pháp nhanh nhất.


2

Giả sử xem xét hai chuỗi s và t.
Cung cấp cho họ một số giá trị.
Khi bạn so sánh chúng bằng cách sử dụng (s == t), nó sẽ trả về giá trị boolean (đúng hoặc sai, 1 hoặc 0).
Nhưng khi bạn so sánh bằng s.compare (t) , biểu thức trả về một giá trị
(i) 0 - nếu s và t bằng nhau
(ii) <0 - hoặc nếu giá trị của ký tự không khớp đầu tiên trong s nhỏ hơn giá trị của t hoặc chiều dài của s nhỏ hơn t.
(iii) > 0 - hoặc nếu giá trị của ký tự chưa từng có đầu tiên trong t nhỏ hơn giá trị của s hoặc độ dài của t nhỏ hơn giá trị của s.


1

Một điều không được đề cập ở đây là nó phụ thuộc vào việc chúng ta so sánh chuỗi với chuỗi c, chuỗi c với chuỗi hay chuỗi với chuỗi.

Một sự khác biệt chính là để so sánh hai đẳng thức kích thước chuỗi được kiểm tra trước khi thực hiện so sánh và điều đó làm cho toán tử == nhanh hơn so sánh.

Đây là so sánh như tôi thấy trên 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; }

mã được định dạng và hiển thị định dạng trong trình chỉnh sửa. Hiển thị đã sai. mở basic_opes.h và tìm toán tử == trên hệ điều hành của bạn. Mã không phải là của tôi là tiêu chuẩn, thực tế là kiểm tra kích thước là những gì còn thiếu trong chủ đề này. Tôi cũng thấy rằng rất nhiều người đồng ý với thông tin không chính xác, bất chấp tiện ích của Stack Overflow.
Dragos
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.