最近span<T>
、コードでを使用するよう提案するか、サイトでを使用するいくつかの回答を見ましたspan
。ある種のコンテナだと思われます。しかし、私はC ++ 17標準ライブラリでそのようなものを見つけることができません。
では、この不可解なspan<T>
とは何か、そしてそれが非標準である場合、なぜ(またはいつ)使用するのが良いのでしょうか?
gsl::span
ではなくstd::span
。以下の私の回答も参照してください。
最近span<T>
、コードでを使用するよう提案するか、サイトでを使用するいくつかの回答を見ましたspan
。ある種のコンテナだと思われます。しかし、私はC ++ 17標準ライブラリでそのようなものを見つけることができません。
では、この不可解なspan<T>
とは何か、そしてそれが非標準である場合、なぜ(またはいつ)使用するのが良いのでしょうか?
gsl::span
ではなくstd::span
。以下の私の回答も参照してください。
回答:
A span<T>
は:
T
メモリ内のどこかにある型の値の連続したシーケンスの非常に軽量な抽象化。struct { T * ptr; std::size_t length; }
、便利なメソッドがたくさんあります。以前は、以前はとして知られarray_view
ていましたarray_ref
。
まず、それを使用しない場合:
std::sort
、std::find_if
、std::copy
およびそれらのスーパージェネリックテンプレート機能のすべて。次に、実際にいつそれを使用するかについて:
使用
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.begin(), my_span.end(), some_predicate);
...しかし、ほとんどのコンテナクラスで発生するオーバーヘッドはまったくありません。
コンパイラーがより多くの作業を実行できるようにします。たとえば、これ:
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 ++コアガイドラインで見つけることができますが、ドリフトをキャッチします。
これは標準ライブラリにありますが、C ++ 20以降のみです。その理由は、C ++コアガイドラインプロジェクトとの関連で考案された現在の形式では、まだかなり新しいからです。これは、2015年以来、形になっているだけです(コメンターが指摘するように、これには以前の履歴があります)。
これは、コアガイドラインのサポートライブラリ(GSL)の一部です。実装:
gsl/span
span<T>
。GSLの実装では、通常、C ++ 14サポートを実装するプラットフォームを想定しています[ 14 ]。これらの代替シングルヘッダー実装は、GSL機能に依存しません。
martinmoene/span-lite
C ++ 98以降が必要tcbrindle/span
C ++ 11以降が必要これらの異なるスパンの実装では、付属するメソッド/サポート関数にいくつかの違いがあることに注意してください。また、C ++ 20の標準ライブラリに入るバージョンとは多少異なる場合があります。
深い読み:あなたがC ++ 17の前に、最終的な公式提案ですべての詳細および設計上の考慮事項を見つけることができ、P0122R7:スパン:オブジェクトのシーケンスの境界に安全な景色ニールMacintoshとステファンJ. Lavavejによります。少し長いですが。また、C ++ 20では、スパン比較セマンティクスが変更されました(Tony van Eerdによるこの短い論文に続いて)。
std::cout << sizeof(buffer) << '\n'
と、100のsizeof(int)が得られることがわかります。
std::array
はコンテナであり、値を所有しています。span
は所有されてい
std::array
完全に別の獣です。その長さはコンパイル時に固定され、Calethが説明したように、参照型ではなく値型です。
@einpoklumは、ここで彼の回答に a span
が何であるかを紹介するのにかなり良い仕事をしています。ただし、彼の回答を読んだ後でも、スパンに不慣れな人が、次のように、完全には回答されていない一連の思考の質問をまだ持っていることは簡単です。
span
C配列とどう違うのですか?それらの1つだけを使用しないのはなぜですか?サイズもわかっているものの1つにすぎないようです...std::array
ますが、それとどうspan
違うのですか?std::vector
ようにstd::array
、あまりにも?span
ですか?それで、それについていくつかの追加の明快さがあります:
彼の答えの直接の引用- 私の追加が太字になっています:
それは何ですか?
A
span<T>
は:
T
メモリ内のどこかにある型の値の連続したシーケンスの非常に軽量な抽象化。- 基本的に、便利なメソッドの束を持つ単一の構造体
{ T * ptr; std::size_t length; }
。(注意これは明らかに異なっているstd::array<>
ためspan
に匹敵する方法、アクセッサ利便性を可能にstd::array
介して、型へのポインタT
タイプおよび長さ(要素の数)T
に対し、std::array
一つ以上の保持実際のコンテナである値型は、T
。)- 非所有型(つまり、「値型」ではなく「参照型」):何も割り当てたり割り当て解除したりすることはなく、スマートポインターを存続させません。
以前は、以前はとして知られ
array_view
ていましたarray_ref
。
これらの太字の部分は理解するために重要ですので、見落としたり、読み違えたりしないでください。A span
は構造体のC配列ではなく、タイプのC配列に配列のT
長さを加えた構造体でもありません(これは基本的にstd::array
コンテナーと同じです)、NORはポインターの構造体のC配列です入力するT
プラス長さではなく、それは、単一の単一含む構造体のタイプへのポインタをT
、そして長さであり、(タイプの要素数T
ポインタを入力することを連続したメモリブロック内)T
にポイントを!このように、使用して追加した唯一のオーバーヘッドは、span
は、ポインタと長さを格納する変数、およびがspan
提供する使用する便利なアクセサ関数です。
これはUNLIKE a std::array<>
です。これはstd::array<>
、が隣接するブロック全体に実際にメモリを割り当てるstd::vector<>
ためです。また、std::vector
基本的にはa std::array
がいっぱいになるたびに動的に増加する(通常はサイズが2倍になる)だけなので、UNLIKEになります。 。A std::array
はサイズが固定されており、a span
はポイントするブロックのメモリを管理することもせず、メモリブロックをポイントするだけで、メモリブロックの長さを知り、C配列内のデータ型を知っています。メモリ内にあり、その連続したメモリ内の要素を操作するための便利なアクセサ関数を提供します。
std::span
C ++ 20以降のC ++標準の一部です。そのドキュメントはhttps://en.cppreference.com/w/cpp/container/spanで読むことができます。今日のabsl::Span<T>(array, length)
C ++ 11以降でのGoogleの使用方法については、以下を参照してください。
std::span<T, Extent>
(Extent
= "シーケンス内の要素の数、またはstd::dynamic_extent
動的の場合。"スパンはメモリを指すだけでアクセスを容易にしますが、管理はしません!):
std::array<T, N>
(サイズが固定されていることに注意してN
ください!):
std::vector<T>
(必要に応じて自動的に動的にサイズが大きくなります):
span
、C ++ 11以降でどのように使用できますか?グーグルは、自社の「Abseil」ライブラリの形で内部C ++ 11ライブラリをオープンソース化しています。このライブラリは、C ++ 14からC ++ 20以降の機能をC ++ 11以降で機能するように提供することを目的としているため、今日の明日の機能を使用できます。彼らが言うには:
C ++標準との互換性
Googleは、C ++ 14、C ++ 17、およびそれ以降に組み込まれている機能に一致またはほぼ一致する多くの抽象化を開発しました。これらの抽象化のAbseilバージョンを使用すると、コードがポストC ++ 11の世界でまだ準備ができていない場合でも、これらの機能に今すぐアクセスできます。
主なリソースとリンクは次のとおりです。
span.h
ヘッダー、およびabsl::Span<T>(array, length)
テンプレートクラス:https : //github.com/abseil/abseil-cpp/blob/master/absl/types/span.h#L189
std::span
2017年に提案されました。C++ 17またはC ++ 20に適用されます。P0122R5、スパン:オブジェクトのシーケンスの境界セーフビューも参照してください。その言語をターゲットに設定しますか?コンパイラが追いつくまでには何年もかかるでしょう。