web-dev-qa-db-ja.com

インターフェイスでstring_viewを使用する必要があるのはいつですか?

提案されたC++ライブラリ を模倣するように設計された内部ライブラリを使用しており、過去数年の間にstd::stringstring_view

新しいインターフェイスに準拠するように、コードを忠実に変更します。残念ながら、私が渡さなければならないのはstd :: stringパラメータと、std :: string戻り値であるものです。だから私のコードは次のようなものから変更されました:

void one_time_setup(const std::string & p1, int p2) {
   api_class api;
   api.setup (p1, special_number_to_string(p2));
}

void one_time_setup(const std::string & p1, int p2) {
   api_class api;
   const std::string p2_storage(special_number_to_string(p2));
   api.setup (string_view(&p1[0], p1.size()), string_view(&p2_storage[0], p2_storage.size()));
}

私は本当にこの変更がAPIクライアントとして私に何をもたらしたのか、(たぶん台無しにするために)より多くのコードを除いてわかりません。 API呼び出しは安全性が低く(APIがパラメーターのストレージを所有しなくなったため)、おそらくプログラム0の作業を保存し(最適化を移動するコンパイラーが今すぐ実行できるため)、それが作業を保存したとしても、それだけです起動後に、またはどこかで大きなループで実行されない、または実行されないいくつかの割り当て。このAPIでは使用できません。

ただし、このアプローチは、たとえば this answer のように、他の場所で見られるアドバイスに従っているようです。

余談ですが、C++ 17以降では、std :: string_viewを優先してconst std :: string&を渡すことは避けてください。

主に最適化を目的として、比較的安全なオブジェクトを安全性の低いオブジェクト(基本的には美化されたポインタと長さ)に普遍的に置き換えることを提唱しているように思われるため、このアドバイスは驚くべきものです。

それで、string_viewをいつ使用するべきか、いつ使用すべきではないのですか?

19
T.E.D.
  1. 値を取る機能は文字列の所有権を取得する必要がありますか?その場合は、std::string(非定数、非参照)を使用してください。このオプションでは、値が呼び出しコンテキストで再び使用されないことがわかっている場合は、値を明示的に移動することもできます。
  2. 機能は文字列を読み取るだけですか?その場合、std::string_view(const、non-ref)を使用してください。これは、string_viewstd::stringchar*を問題なく簡単に処理でき、コピーを作成しないためです。これにより、すべてのconst std::string&パラメータが置き換えられます。

最終的には、あなたのようにstd::string_viewコンストラクターを呼び出す必要がない決して必要はありません。 std::stringには、変換を自動的に処理する 変換演算子 があります。

19
Mgetz

std::string_viewconst char*のいくつかの利点をC++にもたらします:std::stringとは異なり、string_view

  • メモリを所有していない、
  • メモリを割り当てません、
  • あるオフセットで既存の文字列を指すことができます。
  • は、std::string&よりも1レベル少ないポインター間接参照を持っています。

つまり、string_viewは、生のポインタを処理する必要なく、コピーを回避できることがよくあります。

最近のコードでは、std::string_viewconst std::string&関数パラメーターのほぼすべての使用を置き換える必要があります。 std::stringは変換演算子をstd::string_viewに宣言しているため、これはソース互換の変更である必要があります。

文字列ビューが役に立たないからといって特定の使用例ではとにかく文字列を作成する必要がある場所は、それが一般的に悪い考えであることを意味しません。 C++標準ライブラリは、利便性よりも一般性のために最適化される傾向があります。自分で文字列ビューを作成する必要はないはずなので、「安全性が低い」という議論は成り立ちません。

15
amon

主に最適化を目的として、比較的安全なオブジェクトを安全性の低いオブジェクト(基本的には美化されたポインタと長さ)に普遍的に置き換えることを提唱しているように思われるため、このアドバイスは驚くべきものです。

これはこの目的を少し誤解していると思います。これは「最適化」ですが、std::stringを使用する必要がないように自分自身を解き放つと考える必要があります。

C++のユーザーは、さまざまな文字列クラスの数十を作成しています。固定長の文字列クラス、テンプレートサイズがバッファサイズであるSSO最適化クラス、それらを比較するために使用されるハッシュ値を格納する文字列クラスなど。COWベースの文字列を使用する人もいます。 C++プログラマがやりたいことが1つあるとすれば、それは文字列クラスを書くことです。

また、Cライブラリによって作成および所有される文字列は無視されます。裸のchar*s、おそらくある種のサイズ。

したがって、いくつかのライブラリを作成していて、const std::string&を取得する場合、ユーザーは使用していた文字列を取得してstd::stringにコピーする必要があります。たぶん何十回も。

std::stringの文字列固有のインターフェイスにアクセスする必要がある場合、なぜcopy文字列にする必要がありますか?それはそのような無駄です。

パラメータとしてstring_viewを使用しない主な理由は次のとおりです。

  1. 最終的な目標が、NULで終了する文字列(fopenなど)を受け取るインターフェイスに文字列を渡すことである場合。 std::stringは、NULで終了することが保証されています。 string_viewは違います。また、ビューを部分文字列にしてNULで終了しないようにするのは非常に簡単です。 std::stringを部分文字列化すると、部分文字列がNULで終了する範囲にコピーされます。

    私は、まさにこのシナリオのために、特別なNULで終了するstring_viewスタイルのタイプを書きました。ほとんどの操作を実行できますが、NUL終了ステータス(たとえば、最後からトリミング)を壊す操作は実行できません。

  2. 生涯の問題。本当にstd::stringをコピーする必要がある場合、または文字配列を関数呼び出しよりも長く有効にする必要がある場合は、const std::string &を使用して、このことを前もって述べるのが最善です。または、単にstd::stringを値パラメーターとして使用します。そうすれば、そのような文字列がすでにある場合は、すぐにその所有権を主張できます。呼び出し側は、文字列のコピーを保持する必要がない場合は、その文字列に移動できます。

8
Nicol Bolas