In this quick postscript we’ll look into a simple way to clean up our various SDL resources with variadic templates
and template specialization. This will let us clean up all our resources with a single simple call:
cleanup(texA, texB, renderer, window)
instead of calling all the corresponding SDL_Destroy/Free*
functions,
saving ourselves a lot of typing.
We’ll do this by creating a variadic function cleanup
that will take the list of SDL resources to be free’d and then
define specializations of it for each resource we’ll be passing, eg. for SDL_Window
, SDL_Renderer
, SDL_Texture
and so on.
The Variadic Cleanup Function
If you’re unfamiliar with the C++11’s varidic templates and rvalue references and forwarding features it may be useful to do some reading to get some background before continuing on to the implementation. The implementation of our cleanup function however is actually quite simple. We have a single variadic template function that calls one of our specialized cleanup functions and then recurses to iterate through the list of arguments. Since the code for this functionality is so short I’ve left the detailed explanations in the comments, so be sure to read through them.
#ifndef CLEANUP_H
#define CLEANUP_H
#include <utility>
#include <SDL.h>
/*
* Recurse through the list of arguments to clean up, cleaning up
* the first one in the list each iteration.
*/
template<typename T, typename... Args>
void cleanup(T *t, Args&&... args){
//Cleanup the first item in the list
cleanup(t);
//Recurse to clean up the remaining arguments
cleanup(std::forward<Args>(args)...);
}
/*
* These specializations serve to free the passed argument and also provide the
* base cases for the recursive call above, eg. when args is only a single item
* one of the specializations below will be called by
* cleanup(std::forward<Args>(args)...), ending the recursion
* We also make it safe to pass nullptrs to handle situations where we
* don't want to bother finding out which values failed to load (and thus are null)
* but rather just want to clean everything up and let cleanup sort it out
*/
template<>
inline void cleanup<SDL_Window>(SDL_Window *win){
if (!win){
return;
}
SDL_DestroyWindow(win);
}
template<>
inline void cleanup<SDL_Renderer>(SDL_Renderer *ren){
if (!ren){
return;
}
SDL_DestroyRenderer(ren);
}
template<>
inline void cleanup<SDL_Texture>(SDL_Texture *tex){
if (!tex){
return;
}
SDL_DestroyTexture(tex);
}
template<>
inline void cleanup<SDL_Surface>(SDL_Surface *surf){
if (!surf){
return;
}
SDL_FreeSurface(surf);
}
#endif
Using the Variadic Cleanup Function
To see the usefulness of this cleanup utility let’s see how it compresses our calls to the various
SDL_Destroy/Free*
functions throughout Lesson 1.
In lesson 1 if we found that our bitmap or texture wasn’t created successfully we’d need to destroy
the renderer and window before quitting out of SDL and exiting with a failure code. With cleanup
we can compress these two lines down to a single call.
//We compress these two lines down
//SDL_DestroyRenderer(ren);
//SDL_DestroyWindow(win);
//to a single cleanup call:
cleanup(ren, win);
We can also compress the three lines used to free all the resources (texture, renderer and window) at the end of
Lesson 1 down into a single cleanup
call, passing all the resources we want to free.
//We compress these three lines down
//SDL_DestroyTexture(tex);
//SDL_DestroyRenderer(ren);
//SDL_DestroyWindow(win);
//to a single cleanup call:
cleanup(tex, ren, win);
cleanup
can also be used as a drop-in replacement for the various SDL_Destroy/Free*
functions, although this
doesn’t really give us much benefit as far as compressing lines goes.
//Cleanup can also swap in for direct calls turning
//SDL_FreeSurface(bmp);
//into
cleanup(bmp);
End of Postscript
That’s all for this postscript, try out cleanup
yourself by converting your code from Lesson 1 to use it instead of
calling all the SDL_Destroy/Free*
functions manually. If you run into any issues or have any questions
please post a comment below.
I’ll see you again soon in Lesson 2: Don’t Put Everything in Main!