C++ dll/bundle中的Singleton生存期

C++ dll/bundle中的Singleton生存期,c++,singleton,object-lifetime,C++,Singleton,Object Lifetime,如果我在mac上的dll或捆绑包的上下文中创建一个单例类,则该单例类将实例化一次,并由dll的所有实例使用。我正在使用dll作为应用程序的插件。现在我想到了以下事情:如果我使用单例类,它将在插件的多个实例之间共享。然而,这使得有效地管理singleton类的生存期变得困难。我能想到的唯一方法是使用引用计数,并在引用计数为0时使单例删除其自身 有人有更好的想法吗?有没有什么好方法可以将singleton对象限制为dll的一个实例 语言是C++,但解决方案必须在Windows和MAC下工作(这里是捆

如果我在mac上的dll或捆绑包的上下文中创建一个单例类,则该单例类将实例化一次,并由dll的所有实例使用。我正在使用dll作为应用程序的插件。现在我想到了以下事情:如果我使用单例类,它将在插件的多个实例之间共享。然而,这使得有效地管理singleton类的生存期变得困难。我能想到的唯一方法是使用引用计数,并在引用计数为0时使单例删除其自身

有人有更好的想法吗?有没有什么好方法可以将singleton对象限制为dll的一个实例


语言是C++,但解决方案必须在Windows和MAC下工作(这里是捆绑包)。dll或捆绑包的规范由应用程序提供,因此此处无需更改。

通常,静态对象不会在应用程序或库的多个实例之间共享。每个应用程序都有自己的地址空间,不能访问其他应用程序的内存。您是否在使用共享内存或进程间通信


使用引用计数是一个很好的主意,有几个所谓的
“共享指针”
库可以帮助您实现它。下面是我经常使用的一个实现:

这是我关于DLL和C++的黄金法则。 <>强> DLL内部的代码可以用C++编写,但是只有C函数应该从DLL导出。但您可以有“工厂”函数,返回C++接口指针>/P> 从DLL中导出每个类的每个方法会变得很麻烦。组件和接口方面的问题

既然你说的是DLL,这就意味着Windows。这就是答案。COM是你的朋友。制作一个COM DLL,您的引用计数问题就基本解决了。使用ATL模板库(CComObjectRootEx和friends)使实现变得非常简单。用COM导出C++类单体会有点棘手。最简单的方法是使用COM类“包装”singleton,并将所有方法调用转发给真正的singleton实例

现在,如果您不熟悉组件对象模型,那么它在学习曲线中可能有点陡峭。(而且大多数参考书在进程外COM、代理/存根DLL、自动化、IDispatch上花费了太多的时间——这些都与您的问题无关)

现在,如果您没有时间学习COM,这里有一个关于如何在没有COM的情况下实现DLL单例模式的粗略框架

// singleton.h (consumed by DLL and users of your singleton)
// IMySingleton is an interface class.  It only defines pure virtual methods
class IMySingleton
{
public:
    virtual int DoSomething()=0;
    virtual int DoSomethingElse()=0;

    virtual void AddRef()=0;
    virtual void Release()=0;
};

// returns back an instance of IMySingleton with the refcount already at "1"
// This function gets exported out of your DLL(either via .def file or __declexport attribute)
HRESULT GetMySingletonInstance(IMySingleton** ppMySingleton);
// -------------------------------------



// singleton.cpp (compiled into your DLL - but is NOT exported out of the DLL)
class CMySingleton : public IMySingleton
{
public:
    int m_refcount;
    static CMySingleton* s_pInstance;

    // returns an adref'd instance of the singleton
    static CMySingleton* GetInstance()
    {
        if (s_pInstance == NULL)
        {
           s_pInstance = new CMySingleton(); // refcount at 1
        }
        else
        {
           s_pInstance->AddRef();
        }

        return s_pInstance;
    }

    CMySingleton()
    {
       m_refcount = 1;
       // your initialization code goes here
    }

    ~CMySingleton()
    {
       // cleanup code
    }

    int DoSomething()
    {
        /// your code goes here
        return x;
    }

    int DoSomethingElse()
    {
        /// your code goes here
        return y;
    }
    void AddRef() {m_refcount++;}
    void Release()
    {
        m_refcount--;
        if (m_refcount == 0)
        {
            s_pInstance = NULL;
            delete this;
        }
    }

};

// exported out of the DLL
HRESULT GetMySingletonInstance(IMySingleton** ppSingleton)
{
    *ppSingleton = static_cast<IMySingleton*>(CMySingleton::GetInstance());
}
//singleton.h(由DLL和singleton的用户使用)
//IMySingleton是一个接口类。它只定义纯虚拟方法
伊姆辛格尔顿级
{
公众:
虚拟int DoSomething()=0;
虚拟int DoSomethingElse()=0;
虚拟void AddRef()=0;
虚空释放()=0;
};
//返回引用计数已为“1”的IMySingleton实例
//此函数从DLL中导出(通过.def文件或_declexport属性)
HRESULT GetMySingleton实例(IMySingleton**ppMySingleton);
// -------------------------------------
//singleton.cpp(编译到DLL中,但不会从DLL中导出)
CMySingleton类:公共IMySingleton
{
公众:
国际计量单位参考计数;
静态CMySingleton*s_pInstance;
//返回单例的adref实例
静态CMySingleton*GetInstance()
{
如果(s_pInstance==NULL)
{
s_pInstance=new CMySingleton();//1处的引用计数
}
其他的
{
s_pInstance->AddRef();
}
返回s_站姿;
}
CMySingleton()
{
m_refcount=1;
//您的初始化代码在这里
}
~CMySingleton()
{
//清除代码
}
int DoSomething()
{
///你的密码在这里
返回x;
}
int DoSomethingElse()
{
///你的密码在这里
返回y;
}
void AddRef(){m_refcount++;}
无效释放()
{
m_refcount--;
如果(m_refcount==0)
{
s_pInstance=NULL;
删除此项;
}
}
};
//从DLL中导出
HRESULT GetMySingleton实例(IMySingleton**ppSingleton)
{
*ppSingleton=static_cast(CMySingleton::GetInstance());
}

需要访问singleton服务的呼叫者只需调用GetMySingleToInstance一次。当他们离开时,他们只是通过调用指针实例上的release()来释放singleton实例。

我不确定Windows上的工作方式,但在*nix操作系统上,共享对象库中定义的singleton不会在应用程序之间共享,由于每个进程都有自己的地址空间,所以除非您明确使用操作系统的共享内存机制,否则应用程序之间不应共享任何对象。我说的是一个插件的实例,它在一个应用程序中使用。(可能不止一个应用程序,但这会让事情变得更复杂)问题是我不想在第一次需要时创建单例。卸下插件,让单例实例在内存中浮动。这就是我考虑引用计数的原因。对于我阅读和测试的内容,共享一个简单的单例。然而,我目前正在使用捆绑包在mac上进行测试。。。也许windows在这里的行为有所不同。最后,解决方案必须是跨平台的,如果你是说“共享库”,不要使用术语DLL。DLL是特定于Microsoft的共享库实现。感谢您的提示。但是,windows部件实际上是一个dll。这个网站的另一个问题是,dll中的一个单例是跨实例共享的:所以,我不认为windows是一个例外