4

我们用于产品的库之一使用单例来访问它。我很确定它是作为静态实例实现的(它不是开源的)。这适用于单个文档应用程序,但我们的应用程序可能加载了多个文档。我假设对实例的访问是这样写的:

Instance* getInstance() {
    static Instance* inst = new Instance();
    return inst;
}

在这种情况下,是否有某种方法可以稳健地创建多个实例?我唯一能想到的就是拥有更多的流程并使用某种类型的 IPC 将它们捆绑在一起。我想不出什么比hacky更少的了。

我已经要求供应商实现某种类型的会话令牌,这样我就可以拥有多个并发实例,但它们很大而我们很小。

科里

编辑:

  • 该机器是 Windows 机器
  • 全局静态基本上是一个大工厂。我想要某种类型的会话令牌,所以我可以轻松地说“释放此会话中的所有资源”(没有办法重新初始化我所知道的全局静态)

我不会尝试一些狡猾的恶作剧来获得我想要的东西,而是用我自己的类来包装整个事情,并为每个 getter 添加一个会话密钥。在内部,我将跟踪已分配的内容,添加我自己的发布方法以返回资源。由于很多原因,这是次优的,但我想不出更好的主意。

感谢大家的反馈。

4

5 回答 5

5

即使您能够在所有事情都在进程中发生的情况下解决这个特定问题,我也会担心这个单例问题只是冰山一角。该库显然不是为您的场景设计的。

将 DLL 的每个负载隔离到它自己的进程中听起来对我来说是正确的,而且不是 hacky,当然这对你来说可能很昂贵。

于 2009-05-30T00:19:29.203 回答
4

不幸的是,我看不出你的推理有缺陷。供应商已做出决定,您受其约束。他已经决定每个进程一个实例,所以如果你想要多个实例,你必须有多个进程,所有这些都需要。

当然,如果您认为他的限制决定是任意的,并且没有充分的理由,您可以尝试绕过它。从该路径开始的方法是在调试器中执行一些反汇编/汇编步骤。如果您可以确认他的实例工厂的工作方式与您在上面得出的结论完全一致,那么您无疑可以拼凑出一个允许创建多个实例的替代方案。

但当然,这种方法的巨大风险在于,供应商代码库中依赖于他决定拥有单个实例的每一行代码都会成为一个定时炸弹,随时准备在你面前爆炸。该代码对您是不可见的。你准备好打赌这样的线为零吗?我知道克林特伊斯特伍德在这种情况下会说什么;“你觉得朋克很幸运,好吗?” :-)

于 2009-05-30T00:19:03.557 回答
2

没有优雅的方法可以在一个程序空间中拥有单个对象的多个实例——但这是故意的。通常,您只在不希望有多个实例的情况下使用单例。如果供应商使用单例实现了他们的产品,那么选择可能有充分的理由。

也许,如果您更详细地描述您的问题,可能还有其他方法。很难说,根据提供的信息。单例对象有什么作用?为什么需要它的多个实例?

于 2009-05-30T00:27:47.220 回答
1

除了你建议的进程间的东西,我能想出的最好的方法是将 dll 复制到一个新文件并手动加载新的 dll 并导入你为每个创建的实例使用的所有函数。

希望这意味着静态变量不会在不同实例之间发生冲突,因为它们在技术上不在同一个 dll 中。然而,这个解决方案有很多不好的地方,例如每个版本都克隆了 dll 中的所有代码,您将无法使用导入库,而必须手动加载 dll 并导入所有函数。

于 2009-05-30T00:28:00.293 回答
1

我能想到的唯一一件事就是如果你有幸将单例类定义为:

class Document {
public:
    static Document* getInstance() {
        static Document inst;
        return &inst;
    }
    virtual ~Document();
protected:
    Document();
private:
    struct Impl;
    Impl *pImpl;
};

如果您可以对其进行子类化并且子类将可以访问构造函数,那么您可以创建一个可实例化的子类,例如:

class MyDocument: public Document {
public:
    MyDocument(): Document() {
    }
};

这可能并不完全安全,因为实施者可能做出了一些令人讨厌的假设。但它是一个想法或某种方法,可能有一定的工作机会。如果你提到它,供应商可能会接受这个选项......祝你好运。

于 2009-05-30T01:37:30.900 回答