support

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.

 

support

So, let me dive into the details. The GSL consists of five components. Here is a first overview:

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.

Rainer D 6 P2 500x500

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (open)
  • "Generic Programming (Templates) with C++": October 2024
  • "Embedded Programming with Modern C++": October 2024
  • "Clean Code: Best Practices for Modern C++": March 2025
  • 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, Matt Godbolt, and Honey Sukesan.

    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)

    Do you want to stay informed about my mentoring programs? Subscribe Here

    Rainer Grimm
    Yalovastraße 20
    72108 Rottenburg

    Mobil: +49 176 5506 5086
    Mail: schulung@ModernesCpp.de
    Mentoring: www.ModernesCpp.org

    Modernes C++ Mentoring,

     

     

    0 replies

    Leave a Reply

    Want to join the discussion?
    Feel free to contribute!

    Leave a Reply

    Your email address will not be published. Required fields are marked *