C++ 在C++;,如何初始化单例模板中声明的私有类的静态成员?

C++ 在C++;,如何初始化单例模板中声明的私有类的静态成员?,c++,templates,inheritance,singleton,C++,Templates,Inheritance,Singleton,好的,我应该简单地告诉大家,我想创建一个可以从中继承的基本单例类,我想通过一个模板来实现这一点 为了避免内存泄漏,我不直接使用指向实例的指针,而是使用一个私有类来处理删除指针的操作 这是我的实际代码(不工作): 模板类单例 { 私人: 类指针状态 { 私人: T*实例; 公众: PointerInstance():实例(0){} ~PointerInstance(){delete instance;}//无内存泄漏! T*Get() { 如果(!实例){ 实例=新的T(); } 返回实例; }

好的,我应该简单地告诉大家,我想创建一个可以从中继承的基本单例类,我想通过一个模板来实现这一点

为了避免内存泄漏,我不直接使用指向实例的指针,而是使用一个私有类来处理删除指针的操作

这是我的实际代码(不工作):

模板类单例
{
私人:
类指针状态
{
私人:
T*实例;
公众:
PointerInstance():实例(0){}
~PointerInstance(){delete instance;}//无内存泄漏!
T*Get()
{
如果(!实例){
实例=新的T();
}
返回实例;
}
};
静态指针站姿;
公众:
静态T*P站姿(无效)
{
return PInstance.pGet();
};
受保护的:
单态(空){};
~Singleton(void){};
};
下面是典型的派生类声明的外观:

class Child : public Singleton<Child>
{
    friend class Singleton<Child>;
    Child();
    // etc...
};
类子对象:公共单例
{
朋友班单身;
Child();
//等等。。。
};
基本上,我所缺少的是我作为一个单身者制作的每个T类的PInstance实例

我的问题是:是否有一种方法可以一劳永逸地在包含上述代码的Singleton.h中使用几行通用代码,还是我别无选择,只能为每个派生类添加几行特定的代码

(Prime:C++中有没有更好的方法来做一个单独的类?)< /P> <代码>模板 typename Singleton::PointerInstance Singleton::PInstance;


在类之外的标题中。请注意,无论您在
PInstance
的默认构造函数中编写什么,如果您从未调用
pGetInstance
或从未以非模板代码的其他方式引用
PInstance
,则永远不会执行代码。但这应该没问题。

这里有一种更简单的方法,可以编写没有内存泄漏的CRTP单例:

template <class T>
class Singleton
{
  friend class T;
private:
  Singleton() {};
  ~Singleton() {};
  Singleton(const Singleton&); // not implemented
  const Singleton& operator=(const Singleton&); // not implemented

public:
  static T* pGetInstance()
  {
    static T theInstance;
    return &theInstance;
  }
};
模板
单件阶级
{
朋友级T;
私人:
Singleton(){};
~Singleton(){};
Singleton(const Singleton&);//未实现
const Singleton&operator=(const Singleton&);//未实现
公众:
静态T*pGetInstance()
{
静态电阻;
返回&实例;
}
};

用法与问题中的用法相同。

也许您想看看哪一个已经有了通用的
单音持有人类?

首先,一般来说,我建议您尽可能避免使用单音持有人。它们被过度使用了

如果你必须使用它们,我真的不明白这种新的流行方式(一定出现在某个地方的杂志上,因为我看到现在每个人都在使用它)是从Singleton派生出来的。这样做会带来与解决问题一样多的问题

如果您必须有一个,初始化它的最好方法是使用boost::once。 您需要在源代码中执行类似的操作,其中Foo是您的类

这3个都是在Foo和private中静态声明的

Foo* Foo::instance = NULL;
boost::once_flag Foo::flag = BOOST_ONCE_INIT;
void Foo::init()
{
   Foo::instance = new Foo;
};
这也是静态的,是获取实例的公共方法

Foo & Foo::getInstance()
{
   boost::call_once(init, Foo::flag);
   return *Foo::instance;
}
Foo的构造函数不能抛出

请注意,这种技术可以更广泛地用于线程安全的延迟评估情况,而不仅仅是单例。新版本的boost::一次使用标志(现在是struct:careed),二次使用boost::函数,这样您就可以在信息中创建boost::bind


要删除单例,可以在编译单元级别创建boost::shared_ptr并将指针绑定到它,然后使用自定义的deleter,它是类的静态成员,这样delete就可以保持私有。但是,您的删除程序将能够调用delete,并且您的init函数将有权访问deleter函数(它也是私有的)来初始化共享的ptr。

而不是
,为了避免内存泄漏
应该是
,以便使简单的事情变得更复杂
。imho不需要单独的PointerInstance内部类,您只需要静态指针和静态getter(在需要时创建实例)@erjot,您需要指针吗?不能在静态方法中返回对静态实例的引用吗?为什么要返回指针。从pGetInstance()返回引用。它永远不会为NULL,你也不希望用户意外地认为他们可以删除它。这接近于我们所说的“Meyers Singleton”。它应该只返回对实例的引用,而不是指针。@Martin,Valentin:我想让接口尽可能接近问题中的接口。否则,我同意返回一个参考是更好的。好吧,这看起来真的比我正在进行的要好。我只是对“friend class T”有以下错误;然后对各地的私有构造函数都有错误。。。你知道我不做受保护的构造函数怎么办吗?错误:在“类”之后使用模板类型参数“T”错误:友元声明未命名类或function@teupoui在C++0x中,您可以编写
friend T,在C++03中,无法与模板参数成为朋友。受保护的构造函数到底有什么问题?谢谢,但我希望我的程序能够在很多不同的平台上运行,这些平台可能都没有可用的Boost。我更喜欢使用独立的解决方案。谢谢,但我认为Loki的代码对于我来说有点太复杂了(例如,他们的单例文件是946行代码)。我会看一看,但与我已经得到的答案相比,我觉得这里没有什么有趣的地方。好吧,使用singleton类肯定比编写自己的类需要更少的行数。(参见中的Loki一节,举个简短的例子,使用它实际上需要3行代码。您只需支付所需的费用-文件中的许多行是由
Foo* Foo::instance = NULL;
boost::once_flag Foo::flag = BOOST_ONCE_INIT;
void Foo::init()
{
   Foo::instance = new Foo;
};
Foo & Foo::getInstance()
{
   boost::call_once(init, Foo::flag);
   return *Foo::instance;
}