Historique des modifications - Message

Message #10920

Sujet: C++11 Pattern Singleton Thread-safe et Variadic


Type Date Auteur Contenu
Création du message 18-11-2012 18:06:29 OzVessalius
Bonjour,
Voici une petite routine que j'ai fini il y a pas longtemps, il vous faudra un compilateur compatible C++11 qui puisse gérer les variadics template, les threads natif, les type traits. J'utilise g++ 4.7.2 comme compilateur. À ma connaissance, pour MSVC, il faudra avoir MSVC 2012 avec la dernière mise à jour.

Code c++ :


#ifndef SINGLETON_DEFINED_HPP
#define SINGLETON_DEFINED_HPP

#include <thread>
#include <memory>
#include <mutex>

#include <type_traits>

template<class T>
class Singleton
{
    public:
        virtual ~Singleton() { }

        static T* GetInstance()
        {
            if (!m_instance)
            {
                instancier<T, std::is_default_constructible<T>::value>::instanciate(m_instance, m_onceFlag);
                if (!m_instance) // K is not default constructible, crash detected.
                    throw std::runtime_error("Singleton<T> fatal error: K is not default constructible and we ask for construct him with none args... Crash detected.");
            }
            return m_instance.get();

        }

        template<typename... Args>
            static T* GetInstance(Args... args)
            {
                auto f = &Singleton<T>::template _DoInit<Args...>;
                std::call_once(m_onceFlag, f, args...);
                return m_instance.get();
            }
    protected:
        Singleton() { }

    private:
    template<typename K, bool opt>
    struct instancier
    {
        static void instanciate(std::unique_ptr<K>& instance, std::once_flag& onceFlag)
        {
            auto f = [&instance]()
            {
                instance.reset(new K);
            };
            std::call_once(onceFlag, f);
        }
    };
    template<typename K>
    struct instancier<K, false>
    {
        static void instanciate(std::unique_ptr<K>& instance, std::once_flag& onceFlag)
        {

        }
    };

        template<typename... Args>
            static void _DoInit(Args... args)
            {
                m_instance.reset(new T(std::forward<Args>(args)...));
            }
    private:
        static std::unique_ptr<T> m_instance;
        static std::once_flag m_onceFlag;

        Singleton(const Singleton& src) = delete;
        Singleton& operator=(const Singleton& rhs) = delete;
};

#define SINGLETON_DECLARE(className) friend class Singleton<className>; \\
                             className();
#define SINGLETON_DECLARE_DEFAULT_CONSTRUCTOR(className) friend class Singleton<className>;  \\
                             className() { } 

#define SINGLETON_DECLARE_NO_DEFAULT_CONSTRUCTOR(className) friend class Singleton<className>; 

#define SINGLETON_POSSESS_DEFAULT_CONSTRUCTOR(className) namespace std { template<> struct is_default_constructible<className> : public std::integral_constant<bool, true> { }; };
#define SINGLETON_UNPOSSESS_DEFAULT_CONSTRUCTOR(className) namespace std { template<> struct is_default_constructible<className> : public std::integral_constant<bool, false> { }; };


template<class T>
std::unique_ptr<T> Singleton<T>::m_instance = nullptr;
template<class T>
std::once_flag Singleton<T>::m_onceFlag;

#endif

Pour l'utiliser, c'est simple:
Vous prenez une classe, vous la faites dériver de Singleton, le paramètre template est la classe elle-même, ensuite, si vous avez un constructeur par défaut sans comportement "spécial", utilisez la macro SINGLETON_DECLARE_DEFAULT_CONSTRUCTOR(LeNomDeLaClasse), si vous avez un constructeur par défaut avec comportement, utilisez la macro SINGLETON_DECLARE, si vous n'avez pas de constructeur par défaut, utilisez simplement SINGLETON_DECLARE_NO_DEFAULT_CONSTRUCTOR.
Enfin, utilisez la macro SINGLETON_POSSESS_DEFAULT_CONSTRUCTOR si votre classe possède un constructeur par défaut, sinon utilisez SINGLETON_UNPOSSESS_DEFAULT_CONSTRUCTOR, hors de la classe.
Un petit exemple:

Code c++ :


class Unique : public Singleton<Unique>
{
SINGLETON_DECLARE_DEFAULT_CONSTRUCTOR(Unique)
public:
void helloWorld() { std::cout << "Hello, World!" << std::endl; }
};
SINGLETON_POSSESS_DEFAULT_CONSTRUCTOR(Unique)

Unique::GetInstance()->helloWorld();


Cette classe peut throw une exception runtime_error dans le cas où, vous faites appel à GetInstance() alors que la classe n'a pas de constructeur par défaut.

Retour

Options Liens officiels Caractéristiques Statistiques Communauté
Préférences cookies
Corrections
irrlicht
irrklang
irredit
irrxml
Propulsé par Django
xhtml 1.0
css 2.1
884 membres
1440 sujets
11337 messages
Dernier membre inscrit: Saidov17
240 invités en ligne
membre en ligne: -
RSS Feed