1. ホーム
  2. c++

[解決済み】「span」とは何ですか、どんな時に使うのですか?

2022-05-09 22:29:10

質問

最近 span<T> を使用している回答も見受けられます。 span は、ある種のコンテナと思われます。しかし、C++17の標準ライブラリには、そのようなものは見当たりません。

では、この謎の span<T> そして、なぜ(あるいはいつ)、非標準のものを使うのがよいのでしょうか?

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

何ですか?

A span<T> があります。

  • 型の連続した値の非常に軽量な抽象化である。 T メモリ上のどこかにある。
  • 基本的には struct { T * ptr; std::size_t length; } という便利なメソッドをたくさん持っています。
  • 非所有型(すなわち "参照型" 値型ではなく)。割り当てや解放を行わず、スマートポインターを生かさない。

以前は array_view として、さらに以前は array_ref .

どのような場合に使用すればよいですか?

まず、次のような場合です。 ない を使用することです。

  • のような、開始と終了のイテレータのペアを取るようなコードでは使用しないでください。 std::sort , std::find_if , std::copy といった超一般的なテンプレート化された関数のすべてです。
  • 標準ライブラリコンテナ(またはBoostコンテナなど)があり、それがあなたのコードに適していることがわかっている場合は、使用しないでください。これは、それらに取って代わることを意図したものではありません。

では、実際に使用する場合についてです。

使用方法 span<T> (それぞれ span<const T> ) の代わりに、独立した T* (それぞれ const T* を使用した場合、割り当てられた長さやサイズも重要です。そこで、次のような関数に置き換える。

void read_into(int* buffer, size_t buffer_size);

を使っています。

void read_into(span<int> buffer);

なぜ使わなければならないのか?なぜ良いものなのでしょうか?

あ、スパンってすごいんだ! を使うと span ...

  • というのは、そのポインタ+長さ/開始/終了ポインタの組み合わせを、例えば派手でヒモ付きの標準ライブラリコンテナを使うように操作できることを意味します。

    • for (auto& x : my_span) { /* do stuff */ }
    • std::find_if(my_span.cbegin(), my_span.cend(), some_predicate);
    • std::ranges::find_if(my_span, some_predicate); (C++20の場合)

    ... しかし、ほとんどのコンテナクラスで発生するオーバーヘッドが全くありません。

  • は、時にはコンパイラにもっと仕事をさせることができます。例えば、こんな感じです。

    int buffer[BUFFER_SIZE];
    read_into(buffer, BUFFER_SIZE);
    
    

    はこうなります。

    int buffer[BUFFER_SIZE];
    read_into(buffer);
    
    

    ... これは、あなたが望んでいることを実行します。参照 ガイドラインP.5 .

  • を渡すのは、合理的な代替案です。 const vector<T>& は、データがメモリ上で連続していることを期待する場合、関数に追加します。もう、C++の偉い人に叱られることはないのです。

  • は静的解析を容易にするので、コンパイラは愚かなバグを捕らえるのを助けてくれるかもしれません。

  • は、実行時の境界チェックのためのデバッグコンパイルのインスツルメンテーションを可能にする(すなわち span のメソッドには、いくつかの境界チェックのコードが含まれます。 #ifndef NDEBUG ... #endif )

  • は、(span を使用している) あなたのコードが、指されたメモリを所有していないことを示します。

を使用する動機はさらにあります。 span の中に見つけることができます。 C++コアガイドライン - ということなのですが、流れはつかめますよね。

でも、標準ライブラリにあるのですか?

を編集してください。 はい。 std::span は、C++のC++20バージョンで追加されました

なぜC++20だけなのか?このアイデアは新しいものではありませんが、現在の形はC++20と一緒に考え出されたものです。 C++コア・ガイドライン プロジェクトが具体化し始めたのは2015年です。だから時間がかかったんですね。

では、C++17以前の言語を書いている場合、どのように使えばいいのでしょうか?

の一部です。 コア・ガイドライン のサポートライブラリ(GSL)です。実装しています。

  • マイクロソフト / ニール・マッキントッシュの GSL には、スタンドアロンの実装が含まれています。 gsl/span
  • GSL-Lite(ライト は、GSL 全体のシングルヘッダー実装です (そんなに大きくないので、心配しないでください)。 span<T> .

GSL の実装は一般的に C++14 をサポートするプラットフォームを想定しています [... 11 ]. これらの代替のシングルヘッダー実装はGSL機能に依存しません。

なお、これらの異なるspanの実装は、搭載しているメソッドやサポート関数に違いがあり、C++20で標準ライブラリに採用されたバージョンとは多少異なる場合があります。


さらに読む C++17 前の最終的な公式提案である P0122R7 に、すべての詳細と設計上の考慮事項が記載されています。 span: オブジェクトのシーケンスに対する境界安全性の高いビュー Neal Macintosh と Stephan J. Lavavej によるものです。ちょっと長いですけど。また、C++20では、スパン比較のセマンティクスが変更された(以下のように この短い論文 Tony van Eerdによる) 。