{Patterns|Patrones}! Singleton & Non-Copyable

Español


Hello! New post, this time with code!
 
Today I bring you 3 things, I actually wanted to bring you something else, but that other thing needed this 3 foundations:

  • An assert macro that I use, based on the standard assert that allows me to print an specific message when the assertion fails.
  • The non-copyable pattern class, used to prevent something from being copied. As the next one, the pattern works by inheritance, making any class that inherits from it will have its properties.
  • The singleton pattern class. I know singleton abuse is a problem, but the representation is useful sometimes.

Now, before we move on a couple of disclaimers:

  • The singleton implementation makes use of CRTP, I promise, as with SFINAE, I’ll make a couple of post explaining those 2 concepts (as best as I can).
  • This type of singleton has a deterministic time of creation and destruction (as opposed to the traditional singleton that is created the first time it’s needed), the cost of this is a bit of boilerplate code to initialize and destroy it. This kind of tradeoff is done mainly because of 3 things:
    • Determinism: if you’re building a game engine, for example, you don’t want frame spikes because something unexpected (as the initialization of a heavy object) happened.
    • Parameters and constructors: since there will be an explicit point of creation, you can pass parameters to the initialization function without cluttering any get_instance method or create any ambiguity about parameters for creation and when to use them.
    • Multithreading: Same as with determinism, the initialization can be achieved as the only moment in which a critical section is needed, but any further usage of the instance, since it will be a read only operation (obtaining the instance) can be safely done without no other security mechanism.

Disclaimers done, to the code.
 

Assert with message

#ifndef _SIMPLE_ASSERT_H_
#define _SIMPLE_ASSERT_H_
#include <cassert>
    
#define SPL_ASSERT(exp, message)\
    assert((exp) && (message))

#define SPL_FALSE_ASSERT(message)\
    assert(false && (message))

#endif // _SIMPLE_ASSERT_H_

Appart from include guards and cassert obligatory include, there are just 2 macros, the trick of this is just that when the expression fails, it will show both the expression and the message, otherwise, since a string it’s always casted to true the assert works as expected.
 
The second version just forces the expression to false, so that you can see the message. It’s essentially the same as doing assert(!(message)). You can use this version to fail if the code follows a path you know it shouldn’t.
 

Non-Copyable

#ifndef _NON_COPYABLE_H_
#define _NON_COPYABLE_H_

namespace patterns {
    class Non_Copyable {
    public:
        Non_Copyable(const Non_Copyable&) = delete;
        Non_Copyable& operator=(const Non_Copyable&) = delete;
        virtual ~Non_Copyable() = default;
    protected:
        Non_Copyable() = default;
    };
}

#endif // _NON_COPYABLE_H_

There are objects (like the singleton instance) that you don’t want someone else to be able to copy. And you want to fail as fast as possible on that. The simplest way pre-C++11 was to declare the copy ctor & copy assignment private. This is based in the same principle, but using the delete keyword that was introduced with C++11. Also, working as a pattern you only need to make your class inherit from this one and that’s it, non-copyable. If you would ever want a non-movable object, it should be the same but using the move constructor and assignment operators instead.
 

Singleton

This one is the real meat of the article. It’s not complicated but still, let’s go, step by step:

#ifndef _SINGLETON_H_
#define _SINGLETON_H_

#include "non-copyable.h"
#include "simple-assert.h"
#include <utility>

namespace patterns {
    template<typename Base_Type>
    class Singleton : public Non_Copyable {

Include guards, and also include non-copyable.h and simple-assert.h. The utility header will be used to forward parameters, more on this later. As you can see, it inherits from Non_Copyable and it’s a templated class (this is critical to achieve the singleton pattern without caring about the Singleton class).

    protected:
        Singleton() = default;

    private:
        static Base_Type* m_pInst;

The constructor is marked protected, since it only needs to be accessed from the classes inheriting from this pattern. Later, the static instance pointer (so we know it can exist or not, and we don’t need to know about it prior to its initialization). Here is where the template appears, since the instance will be of the Base class, not from Singleton (This is why this implementation makes use of CRTP).

    public:
        template<typename... Base_Type_Arguments>
        static void init(Base_Type_Arguments&& ...args) {
            SPL_ASSERT(!m_pInst, "An instance exists when calling Singleton::init");
            m_pInst = new Base_Type(std::forward<Base_Type_Arguments>(args)...);
        }

Here is something really interesting happening. This is the initialization method used to create the singleton, prior to any usage of it. Appart from the assertion, it makes use of another feature from C++11, ‘variadic templates’. On compilation, this will cause that regardless of the constructor of the Base class, the init method will match the number of parameters and will pass them to the constructor. std::forward() is used here to prevent rvalue/lvalue parameter mismatches, incorrect copies and other issues. Essentially making the call to init as an equal call to the base class constructor.

        static Base_Type& get() {
            return *getp();
        }

        static Base_Type* getp() {
            SPL_ASSERT(m_pInst, "No instance exists when calling Singleton::getp");
            return m_pInst;
        }

        static bool exists() {
            return m_pInst != nullptr;
        }
        
        virtual ~Singleton() {
            SPL_ASSERT(m_pInst, "No instance exists when calling Singleton::~Singleton");
            m_pInst = nullptr;
        }

        static void destroy() {
            SPL_ASSERT(m_pInst, "No instance exists when calling Singleton::destroy");
            delete m_pInst;
        }
    };
}

Assertions here, just for debug purposes 🙂
We have get and getp to access the singleton instance, and note the return value being the base class and not Singleton! Even if we inherit from the pattern, it’s silently there without interfering with the usage of the real class.
We also have the exists method, useful to tell if the singleton is already created (since this singleton implementation doesn’t have automatic initialization).
 
Finally the destructor and the destroy function. The destructor doesn’t have to do anything but clearing the static instance, since it will no longer contain a valid singleton. The real work, the cleaning, is the destroy static method. Deleting the instance in the destructor makes no sense, since if called it’s because the instance is already being deleted.

template <typename Base_Type>
Base_Type* patterns::Singleton<Base_Type>::m_pInst = nullptr;

Outside of the class definition, this line just initializes the instance member to null. It’s done outside of the Singleton definition to prevent minor annoyances from the compilers, it’s the nicest way I find it to work 🙂 (If you have a better one, please leave a comment or even better, a pull request!)
 
That’s all for today. As the last time, here you can find the full source code and an example main file so that you can see how the singleton works in its entirety. Next time, we will put the singleton to work on implementing a Logger for all of your debug needs!

Back to Top




¡Buenas! Nuevo post, ¡esta vez con código!
 
Hoy traigo 3 cosas, en realidad quería mostrar algo diferente, pero necesito estas 3 cosas como base para lo siguiente.

  • Un macro de assert que uso, basado en el assert estándar que además me permite imprimir un mensaje a consola si el assert falla.
  • Una clase con la implementación del patrón “No copiable”, usado para prevenir que algo se copie. Como el siguiente, el patrón funciona a base de herencia, por lo que cualquier clase que herede del patrón adopta sus propiedades.
  • Una clase implementando el patrón Singleton. Sé que abusar de los singletons es un problema, pero aún así son útiles en determinadas ocasiones.

Antes de seguir, un par de consideraciones:

  • Esta implementación de singleton usa algo conocido como CRTP, prometo que, como con SFINAE, voy a crear un par de artículos explicando ambos conceptos (lo mejor que pueda).
  • Este tipo de singleton tiene una creación y destrucción determinista (en contraposición con el singleton tradicional que se crea en el momento en que se necesita por primera vez), el costo de esto es un poco de código extra para inicializar y destruir el singleton explícitamente. Esto es así por 3 razones:
    • Determinismo: si, por ejemplo, estás escribiendo un motor de videojuegos, no querés que de la nada tengas saltos en el framerate porque algo inesperado pasó (como la inicialización de un objeto pesado).
    • Parámetros y constructores: como va a existir una inicialización explícita, se pueden pasar los parámetros de inicialización sin ‘ensuciar’ los ‘getters’ o crear ambigüedad sobre los parámetros de creación y cuándo usarlos.
    • Multithreading: Del mismo modo que con el determinismo, la inicialización es el único momento donde se puede necesitar proteger una sección crítica, quedando cualquier uso posterior de la instancia (obtenerla) libre de requerir ningún mecanismo de seguridad.

Consideraciones hechas, al código.
 

Assert con mensaje

#ifndef _SIMPLE_ASSERT_H_
#define _SIMPLE_ASSERT_H_
#include <cassert>
    
#define SPL_ASSERT(exp, message)\
    assert((exp) && (message))

#define SPL_FALSE_ASSERT(message)\
    assert(false && (message))

#endif // _SIMPLE_ASSERT_H_

Aparte de las ‘include guards’ y el include de cassert obligatorio, hay dos macros nada más. El truco de esto es que cuando la expresión falla, se va a imprimir por consola junto con el mensaje, y de otro modo, como un string siempre se castea a true el assert va a funcionar como se espera.
 
La segunda versión simplemente fuerza la expresión a fallar, para que se imprima el mensaje. Es esencialmente lo mismo que utilizar assert(!(mensaje)). Esta versión se puede utilizar para fallar en caso de que el código siga un camino que no se esperaba que siguiese.
 

Non-Copyable

#ifndef _NON_COPYABLE_H_
#define _NON_COPYABLE_H_

namespace patterns {
    class Non_Copyable {
    public:
        Non_Copyable(const Non_Copyable&) = delete;
        Non_Copyable& operator=(const Non_Copyable&) = delete;
        virtual ~Non_Copyable() = default;
    protected:
        Non_Copyable() = default;
    };
}

#endif // _NON_COPYABLE_H_

Hay objetos (como la instancia de un singleton) que nadie debería poder copiar. Y es genial que se pueda fallar lo antes posible en ese intento. La manera más fácil antes de C++11 era declarar el constructor por copia y la asignación por copia privadas. Esta implementación usa el mismo principio pero aprovechando la nueva keyword delete que fue introducida con C++11. Además, funcionando como un patrón, solo se necesita que la clase herede de él y listo, no-copiable. Si uno quisiera un objeto no-movible (C++11) sería lo mismo pero con los operadores de construcción y asignación por movimiento.
 

Singleton

Acá está la carne del artículo. No es muy complicado pero aún así, paso a paso:

#ifndef _SINGLETON_H_
#define _SINGLETON_H_

#include "non-copyable.h"
#include "simple-assert.h"
#include <utility>

namespace patterns {
    template<typename Base_Type>
    class Singleton : public Non_Copyable {

‘Include guards’ y la inclusión de non-copyable.h y simple-assert.h. El header utility se va a usar para transferir parámetros, más sobre esto luego. Como se ve, hereda de Non_Copyable y es una clase template (crítico para poder usar el patrón sin que importe la clase Singleton).

    protected:
        Singleton() = default;

    private:
        static Base_Type* m_pInst;

El constructor está marcado como protected, porque solo necesita ser accedido desde las clases que hereden de este patrón. Luego, el puntero a la instancia estática (para saber si existe o no y para que no sea necesario saber del objeto antes de su inicialización). Acá es donde aparece el template, ya que la instancia va a ser del tipo Base y no de Singleton (Y además por esto es que la implementación utiliza CRTP).

    public:
        template<typename... Base_Type_Arguments>
        static void init(Base_Type_Arguments&& ...args) {
            SPL_ASSERT(!m_pInst, "An instance exists when calling Singleton::init");
            m_pInst = new Base_Type(std::forward<Base_Type_Arguments>(args)...);
        }

Acá sí hay algo interesante. Este es el método de inicialización que se usa para crear el singleton, antes de usarlo. Aparte del assert, usa otra característicade C++11, ‘variadic templates’. En la compilación, esto va a causar que sin importar el constructor de la clase Base, el método init va a tener el mismo número de parámetros y se los va a pasar al constructor. std::forward() se utiliza para prevenir incompatibilidad de rvalue contra lvalue, copias incorrectas y otros problemas. Esencialmente es lo mismo que realizar la llamada exacta al constructor, en lugar de a init.

        static Base_Type& get() {
            return *getp();
        }

        static Base_Type* getp() {
            SPL_ASSERT(m_pInst, "No instance exists when calling Singleton::getp");
            return m_pInst;
        }

        static bool exists() {
            return m_pInst != nullptr;
        }
        
        virtual ~Singleton() {
            SPL_ASSERT(m_pInst, "No instance exists when calling Singleton::~Singleton");
            m_pInst = nullptr;
        }

        static void destroy() {
            SPL_ASSERT(m_pInst, "No instance exists when calling Singleton::destroy");
            delete m_pInst;
        }
    };
}

Más asserts, para debug 🙂
Tenemos get y getp para acceder a la instancia del singleton y, notar el valor de retorno, que ¡es del tipo de la clase base y no Singleton! Aún si una clase hereda del patrón, éste está allí sin interferir con el uso de esa clase.
Además tenemos exists, útil para saber si la instancia ya fue creada (dado que este singleton no tiene inicialización automática).
 
Finalmente el destructor y la función destroy. El destructor no hace más que limpiar la variable estática, que ya no va a apuntar a un objeto válido. El trabajo real, la limpieza, la realiza el método estático destroy. Matar la instancia en el destructor, no tiene sentido ya que si se está ejecutando es porque la instancia ya se está destruyendo.

template <typename Base_Type>
Base_Type* patterns::Singleton<Base_Type>::m_pInst = nullptr;

Afuera de la definición de la clase, esta línea simplemente inicializa la variable de la instancia a null. Está hecho afuera de la defninición de Singleton para prevenir algunas molestias menores de los compiladores. Es la mejor forma que encontre para que funcione correctamente. (Si tenés una mejor, por favor dejá un comentario o, mejor aún, ¡un pull request!)
 
Esto es todo por hoy. Como la vez pasada, acá está el código completo y un ejemplo de uso, para que puedas ver cómo se usa el singleton y cómo funciona en detalle. La próxima, vamos a usar el singleton para implementar un ‘logger’ ¡para todas tus necesidades de debug!
Inicio

Advertisements

One thought on “{Patterns|Patrones}! Singleton & Non-Copyable

Leave a Reply (Deja una respuesta)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s