web-dev-qa-db-ja.com

`std :: string`の部分文字列に対して` string_view`を効率的に取得する方法

http://en.cppreference.com/w/cpp/string/basic_string_view を参照として使用すると、これをよりエレガントに行う方法がわかりません。

std::string s = "hello world!";
std::string_view v = s;
v = v.substr(6, 5); // "world"

さらに悪いことに、単純なアプローチは落とし穴であり、vに一時的なものへのぶら下がり参照を残します。

std::string s = "hello world!";
std::string_view v(s.substr(6, 5)); // OOPS!

は覚えているようです標準ライブラリにサブストリングをビューとして返すための追加があるかもしれません:

auto v(s.substr_view(6, 5));

次の回避策が考えられます。

std::string_view(s).substr(6, 5);
std::string_view(s.data()+6, 5);
// or even "worse":
std::string_view(s).remove_prefix(6).remove_suffix(1);

率直に言って、私はこれらのどれも非常に素晴らしいとは思いません。今、私が考えることができる最良のことは、エイリアスを使用して、物事を単純にします。

using sv = std::string_view;
sv(s).substr(6, 5);
63
sehe

自由機能のルートがありますが、_std::string_のオーバーロードも提供しない限り、それはスネークピットです。

_#include <string>
#include <string_view>

std::string_view sub_string(
  std::string_view s, 
  std::size_t p, 
  std::size_t n = std::string_view::npos)
{
  return s.substr(p, n);
}

int main()
{
  using namespace std::literals;

  auto source = "foobar"s;

  // this is fine and elegant...
  auto bar = sub_string(source, 3);

  // but uh-oh...
  bar = sub_string("foobar"s, 3);
}
_

私見string_viewのデザイン全体は、セグメンテーション違反と怒っている顧客の世界に私たちを連れ戻すホラーショーです。

更新:

_std::string_のオーバーロードを追加することでさえ、ホラーショーです。微妙なセグメンテーション違反の時限爆弾を見つけることができるかどうかを確認してください...

_#include <string>
#include <string_view>

std::string_view sub_string(std::string_view s, 
  std::size_t p, 
  std::size_t n = std::string_view::npos)
{
  return s.substr(p, n);
}

std::string sub_string(std::string&& s, 
  std::size_t p, 
  std::size_t n = std::string::npos)
{
  return s.substr(p, n);
}

std::string sub_string(std::string const& s, 
  std::size_t p, 
  std::size_t n = std::string::npos)
{
  return s.substr(p, n);
}

int main()
{
  using namespace std::literals;

  auto source = "foobar"s;
  auto bar = sub_string(std::string_view(source), 3);

  // but uh-oh...
  bar = sub_string("foobar"s, 3);
}
_

コンパイラは、ここについて警告するものを何も見つけませんでした。コードレビューもそうではないと確信しています。

以前に言ったことがありますが、c ++委員会の誰かが監視している場合に備えて、もう一度言います_std::string_から_std::string_view_への暗黙的な変換を許可することは、 c ++の評判を落とすのに役立つ

更新

Cpporgのメッセージボードでstring_viewの警告的なプロパティを(私には)かなり上げて、私の懸念は無関心で満たされました。

このグループからのアドバイスのコンセンサスは、関数から_std::string_view_を決して返してはならないということです。つまり、上記の最初の提供は不適切な形式です。

もちろん、これが偶然に(テンプレートの拡張などによって)発生する時間をキャッチするのに役立つコンパイラはありません。

結果として、_std::string_view_は細心の注意を払って使用する必要があります。メモリ管理の観点からは、もう存在しない可能性のある別のオブジェクトの状態を指すコピー可能なポインターと同等だからです。ただし、他のすべての点では値型のように見え、動作します。

したがって、次のようなコード:

_auto s = get_something().get_suffix();
_

get_suffix()が_std::string_を返す場合(値または参照のいずれか)

ただし、get_suffix()が_std::string_view_を返すようにリファクタリングされる場合はUBです。

私の謙虚な見解では、autoを使用して返された文字列を格納するユーザーコードは、呼び出しているライブラリが_std::string_view_の代わりに_std::string const&_を返すようにリファクタリングされると壊れます。

したがって、今後は、少なくとも私にとっては、「ほぼ常に自動」は「文字列の場合を除き、ほぼ常に自動」になる必要があります。

38
Richard Hodges

std :: stringからstd :: string_viewへの変換演算子を使用できます。

std::string s = "hello world!";
std::string_view v = std::string_view(s).substr(6, 5);
4
CAF

これにより、サブストリングstring_viewを効率的に作成できます。

#include <string>
inline
std::string_view substr_view(const std::string &s,size_t from,size_t len) {
  if( from>=s.size() ) return {};
  return std::string_view(s.data()+from,std::min(s.size()-from,len));
}

#include <iostream>
int main(void) {
  std::cout << substr_view("abcd",3,11) << "\n";

  std::string s {"0123456789"};
  std::cout << substr_view(s,3,2) << "\n";

  return 0;
}
0
Alexander