【问题标题】:Singleton template design issue单例模板设计问题
【发布时间】:2011-10-20 08:50:05
【问题描述】:

我目前正在使用以下简单的单例类:

template<class T>
class singleton
    : boost::noncopyable
{
public:
    static T& get_instance()
        {
            assert(sm_instance != nullptr);
            return *static_cast<T*>(sm_instance);
        }

protected:
    singleton()
        {
            assert(sm_instance == nullptr);
            sm_instance = this;
        }
    virtual ~singleton()
        {
            assert(sm_instance != nullptr);
            sm_instance = nullptr;
        }

private:
    static singleton<T>* sm_instance;
};

template<class T> singleton<T>* singleton<T>::sm_instance = nullptr;


class example_one
    : public singleton<example_one>
{
    static example_one instance;
};

example_one example_one::instance;


class example_two
    : singleton<example_two>
{
    static example_two instance;
};

example_two example_two::instance;


// Usage:
example_one& x = example_one::get_instance();
example_two& y = example_two::get_instance();   // not accessible because 'example_two' uses 'private' to inherit from 'singleton<T>'

但是,我想调整一些东西。我不喜欢 get_instance() 被继承到派生类。

我想做这样的事情(非工作代码):

template<class T>
T& get_singleton();

template<class T>
class singleton
{
    friend T& get_singleton()
        {
            assert(sm_instance != nullptr);
            return *static_cast<T*>(sm_instance);
        }   
}

// Usage:
example_two& x = get_singleton<example_two>();

【问题讨论】:

  • 如果你能以任何方式避免它,请不要使用单例 - stackoverflow.com/questions/1392315/…
  • 您的代码没有多大意义。第一个示例检查它的实例字段是否为空,在 CONSTRUCTOR 中(为什么?),然后析构函数更糟糕。您的析构函数应该删除 sm_instance,或者根本不需要析构函数。同样将析构函数内的 instacne 字段设置为 null,完全没有意义。
  • @AngelO'Sphere - 我认为你应该再读一遍代码并考虑一下。

标签: c++ design-patterns singleton


【解决方案1】:

如果您要使用模板函数,为什么还要使用基类:

template<typename T>
T& getInstance()
{
     static T  instance;
     return instance;
}

class example_one: boost::noncopyable
{
       example_one() {}  // Note private construtor
       friend example_one& getInstance<example_one>();
};

class example_two: boost::noncopyable
{
       example_two() {}
       friend example_two& getInstance<example_two>();
};

【讨论】:

  • 这不如我的方法灵活。您需要 friend 声明、私有复制构造函数和赋值运算符,并且不能将编译时间常量传递给 class 的构造函数。
  • 不,我也不会这样做(因为你不会在我的代码中找到单例)。但是你的论点都是有缺陷的。 1)它是一个单例,你不需要向构造函数传递任何东西,只有一个,因此你所有的初始化都是在构造函数中完成的,你不需要传递任何东西。 2) 所有单例都需要私有构造函数/复制构造函数和赋值运算符。 3)我的班级有一个朋友额外的一行代码。您定义了一个不必要的样板子类。我想你会发现我的更整洁、更易于维护。即使一开始使用单顿是一个完全糟糕的主意。
  • 如果我要构建一个单例,我会使用经典的迈尔斯单例。我这样做是因为您试图概括样板。
【解决方案2】:

Andrei Alexandrescu 推广的解决方案使用了一种不同的技术,与这个相比,它有几个好处(其中一个是您想要进行的调整)。它可以在 http://loki-lib.cvs.sourceforge.net/loki-lib/loki/include/loki/Singleton.h?view=markup 获得,但您可能想要下载整个库 ( loki ),或者如果您不需要额外的东西,可以稍微清理一下。然后界面变成:

typedef Loki::SingletonHolder SomeTypeSingleton;
SomeTypeSingleton::Instance(); // 访问单个实例

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 2017-10-12
    相关资源
    最近更新 更多