ガイドライン サポート ライブラリ (GSL) は、C++ コア ガイドラインのガイドラインをサポートするための小さなライブラリです。より良い C++ プログラムを作成するのに役立つはずです。したがって、その主な懸念事項は、メモリの安全性と型の安全性です。それらは、利用可能な GSL のいくつかの実装です。
GSL はヘッダーのみのライブラリであるため、ライブラリの関数と型を非常に簡単に使用できます。最もよく知られている実装は、Github でホストされている Microsoft の実装です:Microsoft/GSL. Microsoft バージョンは C++14 のサポートを必要とし、さまざまなプラットフォームで動作します。主なプラットフォームは次のとおりです。
- Visual Studio 2015 を使用する Windows
- Visual Studio 2017 を使用する Windows
- Clang/LLVM 3.6 を使用した GNU/Linux
- GCC 5.1 を使用する GNU/Linux
しかし、それだけではありません。GitHub にはさらに多くの実装が存在します。 Martin Moene の GSL-lite 実装を明示的に強調したいと思います。彼の実装は、C++98 と C++03 でも機能します。
詳細に入る前に、私の執筆を難しくしている問題が 1 つあります。それは、優れたドキュメントやチュートリアルがないことです。関数と型が何をサポートする必要があるかを理解するには、ライブラリをインストールして単体テストを分析する必要があります。そのようなドキュメントではないと思います。対照的に、GSL の Microsoft 実装のインストールと使用は、Windows と Linux で非常に簡単でした。
それでは、詳細に飛び込みましょう。 GSL は 5 つのコンポーネントで構成されています。最初の概要は次のとおりです:
- GSL.view:ビュー
- span
- string_span
- (cw)zstring
- span
- GSL.所有者
- 所有者
- unique_ptr
- shared_ptr
- dyn_array
- stack_array
- 所有者
- GSL.assert:アサーション
- Expects()
- Ensures()
- GSL.util:ユーティリティ
- 狭い
- narrow_cast()
- not_null
- ついに
- GSL.concept:コンセプト
Range
String
Number
Sortable
Pointer
- ...
C++11 標準には std::unique_ptr と std::shared_ptr があるため、GSL には独自のスマート ポインター gsl::unique_ptr と gsl::shared_ptr があることに疑問を抱くかもしれません。アイデアは非常に単純です。C++11 をサポートしていないコンパイラで GSL を使用できます。 GSL がサポートする多くの関数と型は、C++20 の一部になる可能性があります。それは、少なくとも概念と主張に当てはまります。さらに、残りの部分も今後の C++ 標準の一部になる可能性が非常に高いです。
コンポーネント
ビューを見てみましょう。
GSL.view:ビュー
ビューは決して所有者ではありません。 gsl::span
gsl::span
template <typename T> void copy_n(const T* p, T* q, int n){} template <typename T> void copy(gsl::span<const T> src, gsl::span<T> des){} int main(){ int arr1[] = {1, 2, 3}; int arr2[] = {3, 4, 5}; copy_n(arr1, arr2, 3); // (1) copy(arr1, arr2); // (2) }
関数 copy_n (1) とは対照的に、関数 copy (2) には要素数を指定していません。したがって、エラーの一般的な原因は gsl::span
GSL にはさまざまな種類の所有者がいます。
GSL.owner:所有権ポインタ
std::unique_ptr と std::shared_ptr を知っているので、gsl::unique_ptr と gsl::shared_ptr を知っていると思います。そうでない場合は、スマート ポインターに関する私の投稿をご覧ください。
gsl::owner
gsl::dyn_array
- gsl::dyn_array
実行時に指定される要素の固定サイズを持つヒープ割り当て配列です。 - gsl::stack_array
GSL.assert:アサーション
Expects() のおかげで および Ensures() 、関数の事前条件と事後条件を述べることができます。現在、関数本体に配置する必要がありますが、これは後で関数宣言に移動されます。どちらの機能も契約提案の一部です。
これは、Expects() と Ensures() を使用した簡単な例です。
int area(int height, int width) { Expects(height > 0); auto res = height * width; Ensures(res > 0); return res; }
GSL.util:ユーティリティ
gsl::narrow_cast
- gsl::narrow_cast
その意図のみを表現する static_cast です。縮小変換が発生する可能性があります。 - gsl::narrow
static_cast<T>(x) != x
の場合、narrowing_error 例外をスローする static_castです。 .
gsl::not_null
int getLength(gsl::not_null<const char*> p); // p cannot be a nullptr int getLength(const char* p); // p can be a nullptr
どちらの関数も、その意図を明示的に示しています。 2 つ目は nullptr を受け入れることができます。
ついに スコープの最後で実行される callable を登録できます。
void f(int n) { void* p = malloc(1, n); auto _ = finally([p] { free(p); }); ... }
関数 f の最後に、ラムダ関数 [p] { free(p); } が自動的に呼び出されます。
C++ コア ガイドラインによると、スマート ポインターや STL コンテナーなどの適切なリソース管理を使用できない場合は、finally を最後の手段として検討する必要があります。
GSL.concept:概念
ほとんどの概念は Ranges TS で定義されているため、簡単に説明します。ここに概念に関する私の投稿があります。
最後の言葉
ガイドライン支援ライブラリには感銘を受けました。私が特に気に入っているのは、C++11 準拠のコンパイラを必要としないことです。レガシー コードで使用することもでき、メモリ セーフとタイプ セーフを大幅に向上させることができます。言い忘れましたが、GSL は「同等の手書きの小切手と比較して、ゼロ オーバーヘッドを目指しています。」. それは約束です。
次は?
GSL に少し寄り道した後、C++ コア ガイドラインのルールに戻ります。次の投稿は、関数全般、関数のパラメーター、特にその戻り値についてです。