C++ Core Guideline: The Guideline Support Library
The guidelines support library (GSL) is a small library for supporting the guidelines of the C++ core guidelines. It should help to write better C++ programs. Therefore, its key concerns are memory safety and type safety. They are already a few implementations of the GSL available.
The GSL is a header-only library. Hence, you can use the functions and types of the library quite easily. The best-known implementation is the one from Microsoft, hosted at GitHub: Microsoft/GSL. The Microsoft version requires C++14 support and runs on various platforms. Here are the leading platforms.
- Windows using Visual Studio 2015
- Windows using Visual Studio 2017
- GNU/Linux using Clang/LLVM 3.6
- GNU/Linux using GCC 5.1
But that is not all; there exist more implementations on GitHub. I want explicitly emphasize the GSL-lite implementation of Martin Moene. His implementation even works with C++98 and C++03.
Before I dive into the details, there is one issue that makes my writing difficult: the lack of good documentation or tutorials. To get an idea, of what the function and types should support, you have to install the library and analyze the unit test. That is not the kind of documentation I expect. In contrast, installing and using Microsoft’s implementation of the GSL was relatively easy on Windows and Linux.
So, let me dive into the details. The GSL consists of five components. Here is a first overview:
- GSL.view: Views
- span<T>
- string_span<T>
- (cw)zstring
- GSL.owner
- owner<T>
- unique_ptr<T>
- shared_ptr<T>
- GSL.assert: Assertions
- Expects()
- Ensures()
- GSL.util: Utilities
- narrow
- narrow_cast()
- not_null<T>
- finally
- GSL.concept: Concepts
Range
String
Number
Sortable
Pointer
- …
You may wonder why the GSL has its own smart pointer gsl::unique_ptr and gsl::shared_ptr because the C++11 standard has std::unique_ptr and std::shared_ptr. The idea is simple: you can use the GSL with a compiler that does not support C++11. Many functions and types the GSL support may become part of C++20. That holds, at least for the concepts and the assertions. It is also probable that the remaining parts will become part of upcoming C++ standards.
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
The components
Let’s have a look at the Views,
GSL.view: Views
A view is never an owner. In the case of a gsl::span<T>, it represents a non-owning range of contiguous memory. This can be an array, a pointer with a size, or a std::vector. The same holds for gsl::string_span<T> or a zero-terminated C strings: gsl::(cw)string. The main reason for having a gsl::span<T> is that a plain array will be decayed to a pointer if passed to a function; therefore, the size is lost.
gsl::span<T> automatically deduces the size of the plain array or the std::vector. If you use a pointer, you have to provide the size.
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) }
In contrast to the function copy_n (1), you have not provided the number of elements for the function copy (2). Hence, a common cause of errors is gone with gsl::span<T>.
There are various kinds of owners in the GSL.
GSL.owner: Ownership pointers
I assume you know std::unique_ptr and std::shared_ptr; therefore, you know gsl::unique_ptr and gsl::shared_ptr. If not, here are my posts about smart pointers.
gsl::owner<T*> marks a pointer that owns the referenced object. You should use gsl::owner<T> if you can not use resource handles such as smart pointers or containers. The critical point about the owner is that you must explicitly free the resource. Raw pointers not marked as gsl::owner<T*> are considered non-owning in the C++ core guidelines. Therefore, you do not have to free the resource.
gsl::dyn_array<T> and gsl::stack_array<T> are two new array types.
- gsl::dyn_array<T> is a heap-allocated array with a fixed size of elements specified at run-time.
- gsl::stack_array<T> is a stack-allocated array with a fixed size of elements specified at run-time.
GSL.assert: Assertions
Thanks to Expects() and Ensures(), you can state preconditions and postconditions for your functions. You have to place them in the function body, but this will later be moved to the function declaration. Both functions are part of the contract proposal.
Here is a simple example using Expects() and Ensures().
int area(int height, int width) { Expects(height > 0); auto res = height * width; Ensures(res > 0); return res; }
GSL.util: Utilities
gsl::narrow_cast<T> and gsl::narrow are two new casts.
- gsl::narrow_cast<T> is a static_cast<T> that only expresses its intent. A narrowing conversion may happen.
- gsl::narrow is a static_cast<T> that throws a narrowing_error exception if
static_cast<T>(x) != x
.
gsl::not_null<T*> models a pointer that never should be a nullptr. You will get a compiler error if you set a gsl::not_null<T*> pointer to a nullptr. You can even put a smart pointer such as std::unique_ptr or std::shared_ptr into a gsl::not_null<T*>. Typically, you use gsl::not_null<T*> for function parameters and their return type. Therefore, you can not forget to check if a pointer holds a value.
int getLength(gsl::not_null<const char*> p); // p cannot be a nullptr int getLength(const char* p); // p can be a nullptr
Both functions state their intent explicitly. The second one can accept a nullptr.
finally allows you to register a callable that will run at the end of the scope.
void f(int n) { void* p = malloc(1, n); auto _ = finally([p] { free(p); }); ... }
At the end of the function f, the lambda function [p] { free(p); } will be invoked automatically.
According to the C++ core guidelines, you should consider finally as a last resort if you can not use proper resource management such as smart pointers or STL containers.
GSL.concept: Concepts
I make it short because most concepts are defined in the Ranges TS. Here are my posts on concepts.
My last words
I’m impressed by the guideline support library. What I like, in particular, is that it requires no C++11 conformant compiler. You can even use it in legacy code, making it a lot more memory- and type-safe. I forgot that the GSL “aim for zero-overhead when compared to equivalent hand-written checks.”. That’s a promise.
What’s next?
After my short detour to the GSL I will return to the rules of the C++ core guidelines. The next post is about functions in general, the parameters of functions, and their return value in particular.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery,and Matt Godbolt.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
My special thanks to Embarcadero | |
My special thanks to PVS-Studio | |
My special thanks to Tipi.build | |
My special thanks to Take Up Code | |
My special thanks to SHAVEDYAKS |
Modernes C++ GmbH
Modernes C++ Mentoring (English)
Rainer Grimm
Yalovastraße 20
72108 Rottenburg
Mail: schulung@ModernesCpp.de
Mentoring: www.ModernesCpp.org
Modernes C++ Mentoring,
Leave a Reply
Want to join the discussion?Feel free to contribute!