模板化单例包装器 c++

问题描述 投票:0回答:1

我刚刚对一个奇怪的设计进行了技术测试,在第一次感受到厌恶之后,我开始看到一些有用的用例。我想知道你对此有何看法。 练习目标:

实现一个模板类SingletonWrapper,它可以用任何数据类型(T)实例化,它应该包含一个数据类型T的变量**wrapped**以及相同的getter setter。任何特定数据类型一次只能存在一个实例。尝试创建已存在的相同类型会引发错误。 ...剩下的练习...

所以这是我刚刚为这篇文章所做的尝试(文件Singleton_template.h):

#include <vector>
#include <unordered_map>
#include <memory>
#include <typeindex>
#include <exception>

template<typename T>
class Singleton_template
{
public:
    Singleton_template(T ob)
    {
        std::cout << "Singleton_template()" << std::endl;
        std::type_index typeIdx = typeid(T);
        if (m_singletons.find(typeIdx) == m_singletons.end())
        {
            this->m_Wrapper = ob;
            m_singletons[typeIdx] = this;
        }
        else
        {
            std::cout << "Already exist" << std::endl;
            throw std::exception("Already exist");
        }
    }
    virtual ~Singleton_template() 
    {
        if (auto it = m_singletons.find(typeid(T)); it != m_singletons.end())
        {
            m_singletons.erase(it);
            std::cout << "~Singleton_template() deletion" << std::endl;
        }
    }
    static T Get(T ob)
    {
        return Get();
    }
    static T Get()
    {
        if (auto it = m_singletons.find(typeid(T)); it != m_singletons.end())
        {
            return (*it).second->m_Wrapper;
        }
        return NULL;
    }
    static void Set(T ob)
    {
        if (auto it = m_singletons.find(typeid(T)); it != m_singletons.end())
        {
            (*it).m_Wrapper = ob;
        }
    }
    void operator=(T ob)
    {
        Set(ob);
    }
    T operator==(T ob)
    {
        return(Get(ob));
    }
    T operator<<(T ob)
    {
        return(Get(ob));
    }
    friend std::ostream& operator<<(std::ostream& os, const Singleton_template<T>& singleton) {
        os << Get();
        return os;
    }

private:
    static std::unordered_map<std::type_index, Singleton_template<T>*> m_singletons;
    T m_Wrapper;
};

template <typename T>
std::unordered_map<std::type_index, Singleton_template<T>*> Singleton_template<T>::m_singletons;

以下是如何使用它:

    Singleton_template<int> mint = 118;
    Singleton_template<std::string> mstring = std::string("Hello");
    std::cout << "" << Singleton_template<int>::Get() << " - " << mstring << std::endl;
    Singleton_template<int> hello = 2;

我认为这种设计可以相关的一个场景是一个单例持有者工厂/构建器,其中每个构建对象都以预设对象(所有对象的“ObjectComponent”之母)开始,构建器从它的成员值开始创建所需的对象目的。因此我们可以更新任何工厂(将更新集合构建器)或特定构建器。

我不确定这是否是一个正确的设计,您对这种结构的实用性有什么建议或用例吗?

c++ templates design-patterns singleton
1个回答
0
投票

我不太确定你的设计,甚至不确定你对问题练习的理解......从你所描述的情况来看,所需要的正是这样的:

#include <stdexcept>
#include <iostream>

template <typename T>
class SingletonWrapper
{
  public:
    SingletonWrapper()
    {
        // since singletons are usially instatiated at module level,
        // this will bomb before the program starts.
        if (initd)
        {
            std:: cout << "singleton for this type is already created\n";
            exit(3);
        }

        initd = true;
    }

    static void set(T t)
    {
        wrapped = std::move(t);
    }

    static T& get() 
    {
        return wrapped.get();
    }

  private:
     static bool initd;
     static T wrapped;  // this would be the usual go-to choice.
};

template <typename T>
inline T SingletonWrapper<T>::wrapped;
template <typename T>
inline bool SingletonWrapper<T>::initd = false;

class A {};

SingletonWrapper<A> sa;
SingletonWrapper<A> sb;  // we'll try to create and initialize a second singleton of type A

int main()
{
    sa.set(A{});
}

这不是我设计单例的方式,因为这种设计对包装类提出了一些相当严格和不寻常的要求(其中之一必须至少是可移动的)。这就是为什么单例通常存储指向对象的指针,这意味着您不需要这个时髦的计数器。

我的意思是,您应该探索使用指针,并且可能仅在调用 set() 时抛出异常,这是通常完成的方式。

© www.soinside.com 2019 - 2024. All rights reserved.