一个DLL中的C++模板单例

Ben*_*ler 11 c++ singleton templates

在DLL中AI有一个模板单例:

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

private:
  //All constructors are here
};
Run Code Online (Sandbox Code Playgroud)

在Dll BI中定义一个类Logger.Dlls C,D和E使用Logger,它的访问方式如下:

Singleton<Logger>::instance();
Run Code Online (Sandbox Code Playgroud)

问题是每个dll都实例化它自己的副本

Singleton<Logger>.
Run Code Online (Sandbox Code Playgroud)

而不是使用相同的单例实例.我知道这个问题的解决方案是使用extern模板.这就是d,C,D和E必须包含的内容

extern template class Singleton<Logger>;
Run Code Online (Sandbox Code Playgroud)

和dll B必须包括:

template class Singleton<Logger>;
Run Code Online (Sandbox Code Playgroud)

这仍然会导致创建多个模板实例.我尝试将extern放在所有的dll中但它仍然无法工作我尝试从所有dll中移除extern并且它仍然无法工作.这不是实现模板单例的标准方法吗?这样做的正确方法是什么?

Ste*_*ove 7

这样做的"正确"方法是......不使用单身人士.

如果您希望所有其他代码使用某种类型的相同实例,则为该代码提供对该实例的引用 - 作为函数或构造函数的参数.

使用单例(非模板)与使用全局变量完全相同,这是您应该避免的做法.

使用模板意味着编译器决定如何实例化代码,以及如何访问"实例".您遇到的问题是这个和在DLL中使用静态的组合.

单身人士不好的原因有很多,包括终身问题(确切地说,删除单身人员是否安全?),线程安全问题,全局共享访问问题等等.

总之,如果您只想要一个事物的一个实例,只需创建它的一个实例,并将其传递给需要它的代码.


Jam*_*ess 7

对我__declspec(dllexport)有用的技巧是添加到单例的模板定义中; 从类定义中拆分模板实现,只包含A DLL中的实现; 最后,通过创建一个调用的虚函数强制模板在A DLL中实例化Singleton<Logger>::instance().

因此,在A DLL的头文件中,您可以像这样定义Singleton模板:

template <class T>
class __declspec(dllexport) Singleton {
public:
  static T &instance();
};
Run Code Online (Sandbox Code Playgroud)

然后在你的A DLL的cpp文件中定义模板实现,并强制实例化Singleton<Logger>如下:

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

void instantiate_logger() {
  Singleton<Logger>::instance();
}
Run Code Online (Sandbox Code Playgroud)

至少使用我的编译器,我不需要instantiate_logger从任何地方打电话.只是存在它会强制生成代码.因此,如果此时转储A DLL的导出表,您应该看到一个条目Singleton<Logger>::instance().

现在在您的C DLL和D DLL中,您可以包含带有模板定义的头文件Singleton,但由于没有模板实现,编译器将无法为该模板创建任何代码.这意味着链接器最终会抱怨未解析的外部因素Singleton<Logger>::instance(),但您只需链接A DLL的导出库即可解决此问题.

底线是代码Singleton<Logger>::instance()只在DLL A中实现,因此您永远不会有多个实例.


kvv*_*kvv 5

MSDN说

Win32 DLL映射到调用进程的地址空间.默认情况下,使用DLL的每个进程都有自己的所有DLL全局和静态变量的实例.如果您的DLL需要与其他应用程序加载的其他实例共享数据,您可以使用以下任一方法:

Create named data sections using the data_seg pragma.

Use memory mapped files. See the Win32 documentation about memory mapped files.
Run Code Online (Sandbox Code Playgroud)

http://msdn.microsoft.com/en-us/library/h90dkhs0%28v=vs.80%29.aspx

  • 你读过文章吗?这就是我的想法:您正在尝试在不同的地址空间中共享Singleton <Logger>实例.当您在一个DLL中调用Singleton <Logger> :: instance()时,它会在某个地址空间中返回对本地静态变量的引用,当您在另一个DLL中调用Singleton <Logger> :: instance()时,它会返回对本地静态变量的引用.另一个地址空间,这就是为什么我相信你的第二个dll实例化Singleton <Logger>的另一个实例,因为它没有看到前一个实例.问题非常有趣,我从未遇到过这样的问题. (3认同)