span<T>
最近、コード内で を使用するようにという提案を受けたり、このサイトで を使用している回答をいくつか見たりしましたspan
。これは、何らかのコンテナーであると思われます。しかし、C++17 標準ライブラリにはそのようなものは見つかりません。
では、この神秘的なものとは何でしょうかspan<T>
。また、なぜ (またはいつ) それを使用することがよいのでしょうか。
ベストアンサー1
それは何ですか?
Aspan<T>
は:
T
メモリ内のどこかにある型の連続した値のシーケンスの非常に軽量な抽象化。- 基本的には、
struct { T * ptr; std::size_t length; }
便利なメソッドが多数用意されています。 - 非所有型(つまり「参照型」「値型」ではなく): 何も割り当てたり解放したりすることはなく、スマート ポインターを存続させることもありません。
以前はarray_view
そしてさらに以前array_ref
。
いつ使えばいいですか?
まず、スパンを使用しない場合:
std::sort
開始反復子と終了反復子の任意のペアを取ることができるコード( 、std::find_if
、std::copy
および の他のテンプレート関数など)では span を使用しないでください<algorithm>
。また、任意の範囲を取るコード( を参照)でも span を使用しないでください。情報のためのC++20範囲ライブラリこれらについては、後ほど説明します。スパンには、反復子のペアや範囲よりも厳しい要件があります。要素の連続性とメモリ内の要素の存在です。- コードに適していることがわかっている標準ライブラリ コンテナー (または Boost コンテナーなど) がある場合は、span を使用しないでください。span は既存のコンテナーを置き換えるためのものではありません。
では、実際に span を使用するタイミングについて説明します。
割り当てられた長さやサイズも重要な場合は、独立した(
span<T>
それぞれ ) の代わりに (それぞれ、 )を使用します。したがって、次のような関数を置き換えます。span<const T>
T*
const T*
void read_into(int* buffer, size_t buffer_size);
と:
void read_into(span<int> buffer);
なぜそれを使うべきなのでしょうか? なぜそれが良いことなのでしょうか?
ああ、スパンってすごい!スパンを使うと...
つまり、ポインター + 長さ / 開始 + 終了ポインターの組み合わせを、派手で豪華な標準ライブラリ コンテナーと同じように操作できます。例:
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
sを使用する動機は他にもあります。C++ コアガイドライン- でも、大体の流れは分かります。
しかし、それは標準ライブラリにありますか?
編集:はい、std::span
C++20 バージョンの言語で C++ に追加されました。
なぜC++20だけなのでしょうか?このアイデア自体は新しいものではありませんが、現在の形はC++ コアガイドラインこのプロジェクトは2015年にようやく形になり始めたので、かなり時間がかかりました。
では、C++17 以前を書いている場合はどのように使用すればよいのでしょうか?
それはコアガイドラインのサポートライブラリ (GSL)。実装:
- マイクロソフト / ニール・マッキントッシュグルコーススタンドアロン実装が含まれています:
gsl/span
- GSL-Liteは、 を含む GSL 全体の単一ヘッダー実装です (それほど大きくないので、心配しないでください)
span<T>
。
GSLの実装は、一般的にC++14のサポートを実装したプラットフォームを想定しています[12これらの代替の単一ヘッダー実装は GSL 機能に依存しません。
martinmoene/span-lite
C++98以降が必要tcbrindle/span
C++11以降が必要
これらの異なるスパン実装には、付属するメソッド/サポート関数に若干の違いがあり、C++20 の標準ライブラリに採用されたバージョンとは多少異なる場合があることに注意してください。
さらに詳しい情報: C++17 以前の最終公式提案 P0122R7 にすべての詳細と設計上の考慮事項が記載されています。span: オブジェクトのシーケンスに対する境界セーフなビューニール・マッキントッシュとステファン・J・ラヴァヴェイによる。ちょっと長いですが。また、C++20では、スパンの比較セマンティクスが変更されました(この短い論文トニー・ヴァン・エールド著。