次のコードスニペットを検討してください。
bool foo(const std::string& s) {
return s == "hello"; // comparing against a const char* literal
}
bool bar(const std::string& s) {
return s == "hello"s; // comparing against a std::string literal
}
first sight では、const char*
と比較すると、アセンブリ命令が少なくて済むようです。1、文字列リテラルを使用すると、std::string
がインプレースで構築されるためです。
(編集:回答で指摘されているように、s.compare(const char*)
がfoo()
で効果的に呼び出されるという事実を忘れていました。もちろん、この場合、インプレース構築は行われません。そのため、以下のいくつかの行を取り消し線で表示します。)
ただし、 operator==(const char*, const std::string&)
参照: を見ると
すべての比較は、compare()
メンバー関数を介して行われます。
私の理解から、これは比較を実行するためにとにかくstd::string
を構築する必要があることを意味するので、オーバーヘッドは最終的に同じになると思います(operator==
への呼び出しによって隠されますが) )。
1 アセンブリー命令が少ないからといってコードが高速になるとは限らないことは承知していますが、ここではマイクロベンチマークを行いたくありません。
賢くなりたい場合は、 "string"sv
を返す std::string_view
と比較してください。
"string"
などのリテラルと比較しても、割り当てオーバーヘッドは発生しませんが、nullで終了する文字列として扱われ、付随するすべての欠点があります。
"string"s
は small-string-optimization または allocation elision を除いて割り当てを行います。また、演算子はリテラルの長さを渡されるので、カウントする必要はなく、埋め込まれたnullが許可されます。
そして最後に"string"sv
を使用すると、他の両方のアプローチの長所が組み合わされ、それぞれの短所が回避されます。また、std::string_view
はstd::string
よりもはるかに単純な獣であり、特に後者がすべての最新のものと同じようにSSOを使用している場合はなおさらです。
少なくともC++ 14以降(通常は割り当てを省略できるようになりました)、コンパイラは理論的にすべてのオプションを最後のオプションに最適化し、十分な情報(例では一般に利用可能)と労力を as-ifルールの下で)与えます 。まだまだです。
いいえ、compare()
では、std::string
オペランドのconst char*
を作成する必要はありません。
ここでオーバーロード#4 を使用しています。
文字列リテラルとの比較は、探している「無料」バージョンです。ここでstd::string
をインスタンス化する必要はまったくありません。
私の理解から、これは比較を実行するためにとにかく_
std::string
_を構築する必要があることを意味するので、オーバーヘッドは最終的に同じになると思います(ただし、_operator==
_への呼び出しによって隠されますが) )。
これは、その推論が間違っているところです。 _std::compare
_ は、オペランドをCスタイルのヌル終了文字列として関数に割り当てる必要はありません。過負荷の1つによると:
_int compare( const CharT* s ) const; // (4)
_
4)この文字列を、長さ
Traits::length(s)
でs
が指す文字で始まるnullで終了する文字シーケンスと比較します。
割り当てるかどうかは実装の詳細ですが、シーケンス比較がそうすることは合理的ではないようです。