Menu Share

The Microsoft.GSL Library

by | Published on
category C / C++

In this article I will explore a very nice library for C++ that I recently found. It is called GSL (Guidelines Support Library) and it is an open-source library by Microsoft. It is available on all platforms and under the MIT license. It is a very small but very useful library.

Table of Contents

Introduction

Essentially this GSL library is a collection of useful practices and types that help you enforce those practices. It contains a few utilities and macros as well.

I found this library while I was searching for an implementation of std::span on older language standards like C++ 17. It turns out to have quite a few useful functionalities that one could rely on that are propositions for the C++ standard. These functionalities can save you some time when developing your programs or games in the future and in this article I will metion a few of them.

Useful Constructs

I will now explore the things I found really cool inside the GSL library and that you can implement in pretty much any project starting today.

Span

Let’s start with the span. The span is essentially a wrapper around some raw memory array. It is implemented in C++ 20 as std::span but a lot of projects are with an older standard and with this GSL library you can get to use it from C++ 14. To showcase the usage of a span imagine the typical main function:

int main(int argc, char** argv)

In this main function we take argument count and argument raw array. You could actually use these to make a span. If for example we wanted to make a simple console applicaton that sorts those numbers you would put them in a span and use std::stable_sort so that you don’t have to do it the long and complicated way:

#include <iostream>
#include <gsl/gsl>
#include <algorithm>
#include <cstring>

bool compare_string(const char* left, const char* right) {
    return std::strcmp(left, right) < 0;
}

void print_string(const char* value) {
    std::cout << value << std::endl;
}

int main(int argc, char** argv) {
    gsl::span<char*> arguments(argv, argc);
    std::stable_sort(arguments.begin(), arguments.end(), compare_string);
    std::for_each(arguments.begin(), arguments.end(), print_string);
    return 0;
}

And you can use this span with a lot of other libraries that return pointer array.

Expects & Ensures

These are part of the asserts utilities of GSL. And here you might say that there is a default assert macro in C++. Why not just use it? Well the Expects and Ensures macros actually work on all builds and are not optimized away. They will literally expect that value even on Release builds and will terminate the program if the condition is not met. Both of these macros will also optimize your code for the case where the condition is true.

I use these macros in my BIG2 stack and you can see it in the example section in github:

// ...
glfwSetErrorCallback(glfw_error_callback);
Expects(glfwInit());
// ...

Final Action

The GSL defines a type called final_action. This type allows you to define a function to be called upon exiting a scope or destructing the type. It can be registered as a member of a class even and that will ensure that it cleans up in the end. If we take the previous example when we initialize a graphics library we often need to call glfwTerminate in the end. This is the perfect place to define a final action close to the initialize method. This final action will not be forgotten even if we exit main earlier than expected due to a different fail:

// ...
Expects(glfwInit());
gsl::final_action terminate_glfw([]() { glfwTerminate(); });

GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL);
if (!window)
{
    // Window or OpenGL context creation failed
    // glfwTerminate will still be called when we're exiting the main scope.
    return 1;
}

// ...

// glfwTerminate will be called when we exit this scope.
return 0;

Not Null

GSL defines another useful type called not_null<T>. This type is very useful to signify that you’re passing pointers that are sure to have a value. It helps a lot with nullptr issues since you will be having the error as early as possible as to where you’re passing the nullptr.

It is to be used in places where it is more benefitial to pass a pointer instead of a reference. For example you could make a class or a struct that holds a pointer that could be null at initializatoin but you want to make sure that if you’re calling a setter method to modify it – you will set it to something different than null.

Essentially it is used to signify that you will be using a pointer but null is not a valid value to be passed.

// safer strlength
int length(gsl::not_null<const char*> str) {
    return std::strlen(str);
}

Aliases

GSL also defines some aliases that helps developler remind themselves of good practices. For example if you’re working with raw pointers and you want to signify that a class is an owner of that pointer you could wrap it in gsl::owner<T> which is just an alias to T where T is a pointer type. It doesn’t do anything special except visually reminding you that you need to handle this whenever you no longer need it. GSL also defines gsl::czstring => const char* and gsl::zstring => char* which might make your code more clear when talking about C style string inside your C++ code.

Honorable Mention

There is also a clone library called gsl-lite that supports even older compilers and works in a similar way. It defines the same symbols and if you’re not much of a Microsoft fan you could use that one instead. The Microsoft library works just fine though but it is nice to have some choice.

Technically both libraries adhere to the C++ Guideline Support Library specification which you can find here so the differences are pretty minor in implementation. Both libraries seem to be supported and updated regularly.

Conclusion

I’ve talked a bit about the GSL library and it has a few more useful functionalities. It isn’t as extensive as boost or anything but it defines some small good coding standards that you can start and use today. I hope you found this one useful and you can check more topics about C++ on this blog like how to achieve Rust style enums in C++.

Leave a comment

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