C++中使用CRTP的模板化Singleton策略

Templated Singleton Policy using CRTP in C++

本文关键字:Singleton 策略 CRTP C++      更新时间:2023-10-16

有很多人声称他们的单例实现是健壮和通用的,因为它使用元编程构造。

我的目标是对派生类强制执行singleton策略,这样我就不必显式(手动)将派生类的构造函数声明为private。我认为有一种方法可以天真地添加实例静态变量和getter作为策略,方法是使模板化的singleton成为派生类的朋友。但这一点都不优雅。

我从这段代码开始,它被认为是一个正确的(即完整的)单例设计,同时它显然允许多个实例:

template <class CWrappedClass>
class CSingleton
{
protected:
static CWrappedClass* ms_instance;
private:
CSingleton(){}
CSingleton(const CSingleton& ) {}
CSingleton& operator = (const CSingleton&) {}
public:
static CWrappedClass& GetInstance()
{
if (ms_instance == NULL)
ms_instance = new CWrappedClass;
return *ms_instance;
}
};
template <class CWrappedClass>
CWrappedClass* CSingleton<CWrappedClass>::ms_instance = NULL;

以及这个"策略"的单例客户端,使用CRTP:

class CThing : public CSingleton<CThing>
{
// friend class CSingleton<CThing>; // only if ctor is private!
public:
void DoNothing()
{
std::cout<<" Nothing n";
}
CThing()
{
std::cout<<" single ";
}
};

注意这不是CRTP Singleton策略的正确实施,这只是问题的一部分!

代码不会按原样编译。基本的singleton策略类的构造函数声明为private,因此它不能支持派生实例,除非子类是该类的朋友。人们通常会使构造函数受到保护,这意味着没有什么可以阻止用户使派生类成为非单重类。

问题:是否有任何机制可以在不必手动将派生类的构造函数设为私有的情况下强制执行单例策略?

如果您确实希望使用此模式:

  1. 模板的构造函数应该受到保护,而不是私有的,这样派生类就可以访问它。否则,它自己的构造函数就无法构造基类。

  2. 派生类可以使模板(它是它的基类)成为朋友,并拥有一个私有构造函数。

或者,您可以实现一个宏,该宏实际上是从编译单元中的派生类构造实例的。当我使用类似的模型时(强制修复使用singleton的代码,我无法更改,只能更改实际singleton的实现方式),我选择了这个选项,它实际上在其.cpp文件中通过了boost::once构造。