C ++文字列==とcompare()の違いは?


363

使用に関するいくつかの推奨事項を読みました

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

if( !s.compare(t) ) 
{

の代わりに

if( s == t )
{

私は慣れているし、自然で読みやすいので、ほとんど常に最後のものを使用しています。別の比較関数があることさえ知りませんでした。より正確には、==はcompare()を呼び出すと考えました。

違いは何ですか?どちらの方法でもう一方の方法を優先する必要がありますか?

文字列が別の文字列と同じ値であるかどうかを知る必要がある場合のみを検討しています。


5
前者は真を返し、後者は偽を返し、その逆も同様です。
Viktor Sehr、2012

56
前者はほとんど読めませんが、後者は簡単に読んで理解できます。
Matthieu M.

3
私は次のような「比較」関数を使用します:if(x.compare(y) == 0)<-等号、等しい。IMOを使用!すると、コードが判読できなくなります。
R.マルティーニョフェルナンデス

1
すべてのケースで==が機能するわけではないことに注意してください。文字列は演算子をオーバーロードして比較を実行するため、==は比較の呼び出しと同じです。または、==演算子をオーバーロードしないオブジェクトでこれを試すと、内部コンポーネントではなく、メモリ内のアドレスを比較します。compareの呼び出しはより「安全」です。std :: stringを使用する場合は問題ありません。
DCurro

一つの違い:compareリターン-1場合sよりも低くなるtと、+1場合sよりも大きいtしばらく==復帰true/false。ゼロ以外の整数であるtrue0されます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
読者への注記:関連する違いがあるため、問題の詳細についてはフレデリックハミディの回答を読んでください。2つのテストが間違いなく同じ値を返すことをBo Perssonが示してうれしいですが。!s.compare(t)そして、s == t同じ値を返しますが、比較関数はより多くの情報を提供しs == t、そしてs == tあなたが気にしないときに、より読みやすい、文字列が異なるだけならば、彼らは異なります。
cdgraham

143

std :: string :: compare()int

  • stが等しい場合はゼロに等しく、
  • 未満の場合sはゼロ未満t
  • より大きい場合sはゼロより大きいt

最初のコードスニペットを2番目のコードスニペットと同等にしたい場合は、実際には次のようになります。

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

等価演算子は、等価(つまりその名前)のみをテストし、 bool

ユースケースを詳しくcompare()説明すると、2つの文字列がたまたま異なる場合に2つの文字列が相互にどのように関連しているか(少ないか大きいか)に関心がある場合に役立ちます。PlasmaHHはツリーについて正しく言及しています。たとえば、コンテナをソートしたままにすることを目的とした文字列挿入アルゴリズムや、前述のコンテナの二分探索アルゴリズムなどです。

編集: Steve Jessopがコメントで指摘しているように、compare()クイックソートおよびバイナリ検索アルゴリズムに最も役立ちます。自然ソートと二分検索はstd :: lessでのみ実装できます。


この動作は、木や木に似た生き物を扱うときにしばしば役立ちます。
PlasmaHH、2012

確かにそうです、私はメソッドと等値演算子の違いだけを指摘していました:)
フレデリック・ハミディ

「一方の方法をもう一方の方法に優先させるべきか?」OPは、compare()の可能なユースケースを考えることができないと私に思わせるだけです。
PlasmaHH、2012

2
「2つの文字列が相互にどのように関連しているかに興味がある場合」-このための慣用的なC ++ std::lessは、3ウェイコンパレーターではなく、厳密な弱い順序(この場合は全体の順序でもあります)を使用することです。 。compare()モデル事業のためであるstd::qsortstd::bsearchをモデルにしたものとは反対に、std:sortstd::lower_bound
スティーブジェソップ

30

compare部分文字列を比較するためのオーバーロードがあります。文字列全体を比較する場合は、==演算子を使用する必要があります(呼び出しが行われるかどうかcompareはほとんど関係ありません)。


30

内部的にstring::operator==()はを使用していstring::compare()ます。参照してください:CPlusPlus-string::operator==()

パフォーマンスを比較するために小さなアプリケーションを作成しましたが、デバッグ環境でコードをコンパイルして実行する場合string::compare()は、それよりもわずかに高速ですstring::operator==()。ただし、リリース環境でコードをコンパイルして実行する場合、どちらもほぼ同じです。

参考までに、そのような結論を出すために、1,000,000回の反復を実行しました。

デバッグ環境で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 ==()では、追加の操作を実行する必要があることがわかります(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)

コンパイラが最適化を実行するため、両方のアセンブリコードは非常に似ています。

最後に、私の意見では、パフォーマンスの向上はごくわずかなので、どちらも同じ結果を達成するため(特にリリースビルドの場合)、どちらを優先するかを決定するのは開発者に任せます。


10
「非常に似ている」...違いはありませんね。
xtofl 2016年

私も……同じことです。違いはありません
ワーグナーパトリオタ

1
Tonyの例からの@xtofl生成されたコードはリリースビルドで同一であり、デバッグビルドでは異なります。
JulianHarty 2017

6

compare()strcmp()と同等です。==単純な等価チェックです。compare()従って返しint==ブール値です。


5

compare()戻りますfalse(まあ、0文字列が等しい場合、)ます。

したがって、一方をもう一方と軽く交換することは避けてください。

コードを読みやすくする方を使用します。


3

文字列の等価性を確認するだけの場合は、==演算子を使用します。2つのストリングが等しいかどうかを判別することは、順序を見つける(compare()が提供するものである)ことよりも簡単なので、かもしれません等価演算子を使用するには、あなたのケースでより良いパフォーマンス賢明です。

より長い答え:APIには、文字列の等価性をチェックするメソッドと文字列の順序をチェックするメソッドが用意されています。文字列の等価性が必要なため、等価性演算子を使用します(期待とライブラリ実装者の期待が一致するようにします)。パフォーマンスが重要な場合は、両方のメソッドをテストして、最速を見つけることをお勧めします。


2

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

ここで取り上げられていないことの1つは、文字列をc文字列と比較するか、c文字列を文字列と比較するか、または文字列を文字列と比較するかによって異なります。

主な違いは、2つの文字列を比較する場合、比較を行う前にサイズの等価性がチェックされ、==演算子が比較よりも高速になることです。

これは、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を開き、OSでoperator ==を探します。このコードは私のものではありません。サイズチェックがこのスレッドに欠けているものであるという事実です。また、多くの人がスタックオーバーフローの有用性を否定する誤った情報に同意していることもわかります。
Dragos
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.