1. ホーム
  2. c++

[解決済み] std::string` の部分文字列に対する `string_view` を効率的に取得する方法

2023-02-04 12:28:55

質問

使用方法 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!

I 覚えているようだ 標準ライブラリに、部分文字列をビューとして返す機能が追加されるかもしれない、というようなことを思い出した。

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);

どのように解決するのですか?

フリーファンクションのルートもありますが 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);
}

IMHOでは、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++の評判を落とすだけのひどいエラーです。 .

アップデート

この (私にとって) かなり心配な string_view のプロパティを cpporg メッセージボードに提起しましたが、私の懸念は無関心に扱われました。

このグループからのアドバイスのコンセンサスは、次のとおりです。 std::string_view は決して関数から返してはいけないということです。つまり、上記の私の最初の提案は悪い形式だということです。

もちろん、(例えばテンプレート展開によって)これが偶然に起こる時をキャッチするためのコンパイラの助けはありません。

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

したがって、次のようなコードになります。

auto s = get_something().get_suffix();

安全なのは get_suffix()std::string (を返します(値または参照による)。

を返すようにリファクタリングされた場合、UB となります。 std::string_view .

つまり、私の考えでは、返された文字列を格納するユーザコードはすべて auto を返すようにリファクタリングされた場合、そのライブラリは壊れてしまいます。 std::string_view の代わりに std::string const& .

ですからこれからは、少なくとも私にとっては、"almost always auto" は "almost always auto, except when it's strings" にならなければならないでしょう。