C++中string的==和compare()有什么区别?

481

我刚刚阅读了一些关于使用

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

if( !s.compare(t) ) 
{

代替
if( s == t )
{

我几乎总是使用最后一种方法,因为我已经习惯了它,而且它更自然、更易读。我甚至不知道有一个单独的比较函数。 更准确地说,我以为“==”会调用compare()。
这两种方法有什么区别?在哪些情况下应该优先考虑其中一种?
我只考虑需要知道一个字符串是否与另一个字符串相同的情况。

10
第一个会返回 true,而后一个会返回 false,反之亦然。 - Viktor Sehr
90
前者几乎无法阅读,而后者易于阅读和理解。 - Matthieu M.
8
我使用“比较”函数的方式是这样的:if(x.compare(y) == 0) <- 等号,表示相等。在我看来,只使用 ! 只会使代码难以阅读。 - R. Martinho Fernandes
4
需要注意的是,在每种情况下,== 都不会对您起作用。string 重载了运算符以执行比较,因此 == 等同于调用比较。或者,如果您尝试在未重载 == 运算符的对象上使用它,则将比较它们在内存中的地址,而不是它们的内部组件。调用 compare 更加“安全”。但在使用 std::string 的情况下,您是安全的。 - DCurro
2
一个区别是:compare 如果s小于t则返回-1,如果s大于t则返回+1,而==则返回true/false。非零整数为true,0为false - ghchoi
第二个程序更容易被压缩算法压缩,因为程序中可能会有更多的“==”。 - huseyin tugrul buyukisik
9个回答

567

这是标准对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;

返回值:lhs.compare(rhs) == 0。


20
读者请注意:由于存在相关差异,请阅读Frédéric Hamidi的回答以了解详细信息。尽管我很高兴Bo Persson表明两个测试肯定会返回相同的值,但是 !s.compare(t)s == t 将返回相同的值,但是 compare 函数提供了比s == t更多的信息,当您只关心字符串是否不同而不关心它们不同的方式时,s == t 更易读。 - cdgraham

192

std::string::compare()函数返回一个int值:

  • 如果st相等,则返回零。
  • 如果s小于t,则返回小于零的值。
  • 如果s大于t,则返回大于零的值。

如果您想让第一个代码片段与第二个代码片段等效,则应该实际上这样编写:

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

等号运算符只测试相等性(因此它的名称)并返回一个bool
为了详细说明用例,如果两个字符串不同,compare()可能很有用,如果您对它们之间的关系(较小或较大)感兴趣。PlasmaHH正确地提到了树,它也可以是一个字符串插入算法,旨在保持容器排序,对于上述容器的二分查找算法等等。 编辑:正如Steve Jessop在评论中指出的那样,compare()对于快速排序和二分搜索算法最有用。自然排序和二分搜索可以仅使用std::less实现。

1
请注意,当处理树或类似树形结构时,这种行为通常非常有用。 - PlasmaHH
确实如此,我只是在指出方法和等号运算符之间的区别 :) - Frédéric Hamidi
在什么情况下应该更倾向于使用其中一种方式?这让我想到楼主可能想不到使用compare()的可能用例。 - PlasmaHH
3
如果你对这两个字符串间的关系感兴趣,建议使用严格弱序(例如 std::less,在这种情况下也是全序)而不是三路比较器。compare() 适用于基于 std::qsortstd::bsearch 的操作,而不是基于 std::sortstd::lower_bound 的操作。 - Steve Jessop

56

在内部, string::operator==() 使用了 string::compare()。请参考:CPlusPlus - string::operator==()

我写了一个小程序来比较性能,显然如果您在调试环境下编译和运行代码,string::compare()string::operator==() 稍微快一点。但是如果您在发布环境下编译和运行代码,两者几乎相同。

顺便说一下,我运行了100万次迭代才得出这样的结论。

为了证明为什么在调试环境中 string::compare 更快,我查看了汇编代码:

调试版本

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)

你可以看到,在string::operator==()中,需要执行额外的操作(add esp, 8和movzx edx,al)。

发布版本

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)

两种汇编代码非常相似,因为编译器执行了优化。

最后,在我看来,性能提升可以忽略不计,因此我真的会把选择权交给开发者决定哪个更好,因为两个都可以达到相同的结果(特别是在发布构建时)。


15
“非常相似”... 我看不出有什么区别,你呢? - xtofl
我也是这么认为...它们是同一件事。没有区别。 - Wagner Patriota
4
根据Tony的示例,生成的代码在发布版本中是相同的,在调试版本中则不同。 - JulianHarty

32

compare有用于比较子字符串的重载函数。如果您要比较整个字符串,请直接使用==运算符(它是否调用compare函数基本上无关紧要)。


7

compare() 等同于 strcmp()。 == 是简单的相等检查。 因此,compare() 返回一个 int== 是布尔类型。


7

compare()函数在字符串相等时返回false(或者说是0)。

所以不要轻易将它们互换。

使用哪个更容易让代码可读就用哪个。


4

这里没有涵盖的一件事是,它取决于我们比较字符串与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 并查找您的操作系统上的 operator==。代码不是我的,而是标准的。本线程中缺失的是大小检查的事实。我还看到许多人对不正确的信息表示同意,这违反了 Stack Overflow 的实用性。 - Dragos

3
如果您只想检查字符串是否相等,请使用 == 运算符。判断两个字符串是否相等比找到排序(这就是 compare() 提供的)更简单,所以在您的情况下使用相等运算符可能会更好地提升性能。
更长的答案: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的长度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接