std::string_view
は C++17 に導入されており、 の代わりにこれを使用することが広く推奨されていますconst std::string&
。
理由の1つはパフォーマンスです。
パラメータ型として使用した場合と比べて、どれくらい速くなるのか、具体的に 説明してもらえますか? (呼び出し側にコピーは作成されないと仮定します)std::string_view
const std::string&
ベストアンサー1
std::string_view
いくつかのケースではより高速になります。
まず、 では、std::string const&
データが に存在する必要がありstd::string
、生の C 配列、char const*
C API によって返される 、std::vector<char>
何らかのデシリアライゼーション エンジンによって生成される などであってはなりません。 形式変換を回避することで、バイトのコピーが回避され、(文字列が特定の実装の SBO¹ よりも長い場合std::string
) メモリ割り当てが回避されます。
void foo( std::string_view bob ) {
std::cout << bob << "\n";
}
int main(int argc, char const*const* argv) {
foo( "This is a string long enough to avoid the std::string SBO" );
if (argc > 1)
foo( argv[1] );
}
この場合、割り当ては行われませんが、の代わりにが使用されるstring_view
場合は割り当てが行われます。foo
std::string const&
string_view
2 つ目の非常に大きな理由は、コピーなしでサブ文字列を操作できることです。2 GB の JSON 文字列 (!)² を解析しているとします。これを に解析すると、std::string
ノードの名前または値を格納する各解析ノードは、 2 GB の文字列から元のデータをローカル ノードにコピーします。
代わりに、s に解析するとstd::string_view
、ノードは元のデータを参照します。これにより、数百万の割り当てを節約し、解析中のメモリ要件を半分に減らすことができます。
得られるスピードアップは、驚くほどです。
これは極端なケースですが、他の「部分文字列を取得して操作する」ケースでも、 を使用するとかなりの速度向上が得られますstring_view
。
決定において重要なのは、 を使用することで何を失うかということですstd::string_view
。
まず、所有権を失います。 は、他の誰かのメモリへの愚かなポインタです。これを追跡するのは頭痛の種です。もちろん、から へstring_view
の場合も同じです。const&
std::string
2 番目に、暗黙的な null 終了がなくなります。これですべてです。したがって、同じ文字列が 3 つの関数に渡され、そのすべてが null 終了文字を必要とする場合は、std::string
1 回に変換するのが賢明です。したがって、コードに null 終了文字が必要であることがわかっていて、C スタイルのソース バッファーなどから文字列が供給されることを想定していない場合は、 を使用しますstd::string const&
。それ以外の場合は を使用しますstd::string_view
。
もし に null で終了しているかどうかを示すフラグ (またはもっと高度なフラグ) があった場合std::string_view
、 を使用する最後の理由さえもなくなりますstd::string const&
。
std::string
を なしで取る方const&
が よりも最適な場合がありますstd::string_view
。呼び出し後に文字列のコピーを無期限に所有する必要がある場合は、値渡しが効率的です。SBO の場合 (割り当ては行われず、複製するためにいくつかの文字のコピーのみ)、またはヒープに割り当てられたバッファをローカル に移動するstd::string
ことができます。 と の 2 つのオーバーロードがあるstd::string&&
とstd::string_view
高速になるかもしれませんが、わずかであり、適度なコード膨張が発生します (これにより、速度の向上がすべて失われる可能性があります)。
¹ 小さなバッファの最適化
² 実際の使用例。