【问题标题】:Template singleton base class in shared object共享对象中的模板单例基类
【发布时间】:2014-05-24 17:58:25
【问题描述】:

我目前正在将我的项目从 Windows 移植到 Linux。

该项目由一个“主”共享库、几个插件(也是共享库)和一个启动器应用程序组成。

在“主”共享库中有一个模板单例类,另一个类可以从该类继承以使用单例模式。

模板单例类实现如下:

    template<class T>
    class Singleton
    {
    public:
        static T* getInstance()
        {
          if(!m_Instance)
          {
            m_Instance = new T();
          }

          return m_Instance; 
        }
    private:
        static T* m_Instance;

    protected:
        Singleton()
        {
          assert(!m_Instance);
          m_Instance = (T*)this;
        }

        ~Singleton()
        {
          m_Instance = 0;
        }
    };

template<class T> T* Singleton<T>::m_Instance = 0;

从 Singleton 类继承的类是 - 例如 - Logger 类。 所以每当我打电话时

Logger::getInstance()

我得到了一个有效的记录器类实例。

对于 Windows,这适用于多个 DLL。

如果我在“主”dll 中实例化记录器并尝试在插件 A 和 B 中获取实例,它将始终返回相同的实例。

但在 Linux 上我无法重现此行为。对于插件 A 和 B,断言

assert(!m_Instance);

触发,程序停止。

我必须做些什么才能获得与在 Windows 中的 dll 相同的行为?

我尝试使用 -rdynamic 链接,但不幸的是这并没有解决问题。

【问题讨论】:

  • 反模式单例的模板类完全没用
  • getInstance 成员函数中的条件是否会成立?
  • @DieterLücking:Andrei Alexandrescu 的经典著作《现代 C++ 设计》包含一些很好的讨论和代码示例。您可能会在 Loki 库中找到该代码。
  • @faranwath 是的,在调用 getInstance 之前没有实例化单例时
  • @FelixK。是的,但我喜欢显式实例化我可能拥有的任何单例,而不是依赖延迟初始化。

标签: c++ linux shared-libraries


【解决方案1】:

恕我直言,您可以获得满足您要求的最接近的东西是使用following pattern

#include <iostream>

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

protected:
    Singleton() {}

private:
    Singleton(const Singleton<Derived>&);
    Singleton<Derived>& operator=(const Singleton<Derived>&);
};

class ASingleton : public Singleton<ASingleton> {
public:
    void foo() { std::cout << "foo() called ..." << std::endl; }
};

int main() {
    ASingleton& a = ASingleton::instance();
    a.foo();
    return 0;
}

您希望通过接口访问的任何内容都可以使用多重继承进行注入。虽然使用 Singleton&lt;Derived&gt; 基类的好处有点值得怀疑,但它只是提供了狭窄的 instance() 实现。

【讨论】:

  • Meyer 的单例在 OP 的情况下存在问题,它用于记录器,即当某些全局对象的析构函数理想情况下应该记录某些内容时,它可能已经被销毁。一种常见的解决方案是故意从不销毁的动态分配的单例,我认为这就是 OP 的目标。另一个可能的解决方案是凤凰鸟娱乐计划。但是这里还有另一个更严重的问题,这就是我删除答案的原因,即从不同的 DLL 访问单例。我可以轻松地在每个 DLL 中设想一个实例。 :-(
  • @Cheersandhth.-Alf 实际上不同的 DLL 只访问一个实例,但是当使用 Unix *.so(共享对象)动态库时,情况并非如此
  • 也许我不明白你的答案,但我不是要求不同/更好的实现,而是如何构建我的库,当从其他库调用 getInstance() 时,我总是会得到同一个例子。现在,我正在为我从中调用 getInstance() 的每个不同库获取一个新实例。 (不过,仅在 Linux 下。在 Windows 上 getInstance() 总是返回相同的实例,即使我从不同的动态库中调用它。)
  • @FelixK。对不起,我似乎错过了这一点。我以为您主要是在询问正确的模板模式。我不知道这个实现是否解决了您在不同.so 共享库上进行多次实例化的问题。无论如何,这种创建实例的方式比使用new() 好得多,并且解决了许多问题。
猜你喜欢
  • 1970-01-01
  • 2022-10-14
  • 2012-10-15
  • 1970-01-01
  • 1970-01-01
  • 2015-07-04
  • 2011-01-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多