Singleton mixin C ++

Summary: How to create a singleton mixin in C ++? I am trying to avoid copying the same function get_instance(), private constructor, etc. But I can’t figure out how to do this mixin, because the static instance will be shared by everything that inherits from mixin.

It is easy to make each derived class single, but is there a way to do this without duplicating code? Thanks so much for your help, I'm at a standstill.

Code: I am writing a program with a class Registryto search for objects by name.

#include <string>
#include <memory>
#include <map>
#include <string>
#include <assert.h>

template <typename T>
class Registry
{
private:
  // make private so that the class can't be instantiated and must be used via get_instance
  Registry() {}
protected:
  std::map<std::string, std::shared_ptr<T> > name_to_object_ptr;
public:
  static Registry<T> & get_instance()
  {
    static Registry<T> instance;
    return instance;
  }
  void register_name(const std::string & name, T*obj_ptr)
  {
    assert( name_to_object_ptr.count(name) == 0 );
    name_to_object_ptr[name] = std::shared_ptr<T>(obj_ptr);
  }
  const std::shared_ptr<T> & lookup_name(const std::string & name)
  {
    assert( name_to_object_ptr.count(name) > 0 );
    return name_to_object_ptr[name];
  }
  int size() const
  {
    return name_to_object_ptr.size();
  }
};

My Registryclass is singleton; it must be singleton (so that registered objects do not disappear).

class DerivedRegistryA : public Registry<int>
{
};

class DerivedRegistryB : public Registry<int>
{
};

int main()
{
  DerivedRegistryA::get_instance().register_name(std::string("one"), new int(1));
  std::cout << DerivedRegistryA::get_instance().size() << std::endl;
  DerivedRegistryA::get_instance().register_name(std::string("two"), new int(2));
  std::cout << DerivedRegistryA::get_instance().size() << std::endl;
  DerivedRegistryA::get_instance().register_name(std::string("three"), new int(3));
  std::cout << DerivedRegistryA::get_instance().size() << std::endl;

  DerivedRegistryB::get_instance().register_name(std::string("four"), new int(4));
  std::cout << DerivedRegistryB::get_instance().size() << std::endl;

  return 0;
}

Conclusion:

1
2
3
4

Desired conclusion:

1
2
3
1

+3
5

. , .

, factory Registry. RegAccess:

template <typename RegType>
class RegAccess
{
public:
  static RegType & get_instance()
  {
    static RegType instance;
    return instance;
  }
};

, :

  • RegAccess<Registry<T> > Registry<T> ( , , - Registry<T>)
  • Registry protected, private ( )
  • get_instance Registry<T>

:

int main()
{
  RegAccess<DerivedRegistryA>::get_instance().register_name(std::string("one"), new int(1));
  std::cout << RegAccess<DerivedRegistryA>::get_instance().size() << std::endl;
  RegAccess<DerivedRegistryA>::get_instance().register_name(std::string("two"), new int(2));
  std::cout << RegAccess<DerivedRegistryA>::get_instance().size() << std::endl;
  RegAccess<DerivedRegistryA>::get_instance().register_name(std::string("three"), new int(3));
  std::cout << RegAccess<DerivedRegistryA>::get_instance().size() << std::endl;

  RegAccess<DerivedRegistryB>::get_instance().register_name(std::string("four"), new int(4));
  std::cout << RegAccess<DerivedRegistryB>::get_instance().size() << std::endl;

  return 0;
}

, .

+3

. .

template <typename T, typename Mixie>
class Registry
{
private:
  Registry() {}
protected:
  std::map<std::string, boost::shared_ptr<T> > name_to_object_ptr;
public:
  static Registry<T,Mixie> & get_instance()
  {
    static Registry<T,Mixie> instance;
    return instance;
  }
  ...
};
class DerivedRegistryA : public Registry<int,DerivedRegistryA>
{
};

class DerivedRegistryB : public Registry<int,DerivedRegistryB>
{
};
+4

, DerivedRegistryA DerivedRegistryB name_to_object_ptr

get_instance Registry<T> DerivedRegistry, DerivedRegistry Registry<int>, . . static. .

, instance, Registry<T>.

- . , , . .

get_instance Registry

template <typename T>
class Singleton{
  public:
  static T& get_instance(){
    static T& instance;
    return instance;
  }
};

class DerivedRegistryA : public Registry<int>, public Singleton<DerivedRegistryA>{

};

, Singleton ,

+2

: Aaarrg a Singleton: x (*)

...

1: .

template <typename T>
class Registry {
public:
    typedef std::string Key;
    typedef std::shared_ptr<T> ItemPtr;

    Registry() {}

    Registry(Registry const&) = delete;
    Registry& operator=(Registry const&) = delete;

    ItemPtr find(Key) const;

    void insert(Key, ItemPtr);

private:
    typedef std::map<Key, ItemPtr> StoreType;
    StoreType _store;
}; // class Registry

2: Singleton.

template <typename Object, typename>
class Singleton {
public:
    static Object& GetMutableInstance() {
        static Object O;
        return O;
    }

    static Object const& GetInstance() { return GetMutableInstance(); }

private:
    Singleton() = delete;
}; // class Singleton

: ( ) . (, , ) . .

3: .

struct TypeA {};
typedef Singleton<Registry<int>, TypeA> RegistryA;

int main() {
    RegistryA::GetMutableInstance().insert("toto", std::make_shared(3));
}

(*) ?

, . , , , . .

( , ..); crappiness ( ) , , (GetInstance hell).

( Velociraptor, , ).

, , //, . , .

+2

this will help solve your problem. Keep in mind that this singleton is not thread safe. But you can change it if you need to.

See CRTP for more details .

#include <iostream>
#include <map>
#include <string>

// simple singleton
template <class T>
class Singleton {
public:
    static T& Instance() { static T instance; return instance; }
protected:
    Singleton(){}
};

// your Registry Base
template <class T>
class Registry : public Singleton< Registry<T> > {
    friend class Singleton<Registry>;
public:
    void register_name( const std::string& name, T value ){ m_data[name] = value; }
    const T& lookup_name( const std::string& name ){ return m_data[name]; }

private:
    Registry(){}
    Registry(const Registry&){} // to prevent copies, you have to use ::Instance()

    std::map<std::string, T> m_data;
};

int main(int argc, char *argv[])
{
    Registry<int>& instance = Registry<int>::Instance();

    instance.register_name("Value1",1);
    Registry<int>::Instance().register_name("Value2",2);

    int value = instance.lookup_name("Value1");
    std::cout << "Value1=" << value << std::endl;
    std::cout << "Value2=" << Registry<int>::Instance().lookup_name("Value2") << std::endl;

    return 0;
}
+2
source

All Articles