2

我有一个包含 3 个项目的应用程序(在 MS Visual Studio 中):

  • main(包含main函数的那个​​)
  • 设备(模拟一些硬件设备)
  • config(包含其他两个项目的一些配置)

所以依赖图是:

  • main取决于device,这取决于配置
  • 主要取决于配置

config项目包含一个 Singleton,其中包含一些配置参数。

我决定把设备项目变成一个 DLL。当我这样做时,似乎我在配置项目中有两个单例实例!我想这是一个经典问题,它可能有一个很好的解决方案。那么我该如何解决这个问题?

我用以下(相对较小的)代码重现了这个问题。当然,就我而言,有大约 30 个项目,而不仅仅是 3 个。我只想制作 1 个 DLL(如果可能的话)。


// config.h
#pragma once
#include <string>
#include <map>
class Config
{
public:
    static void Initialize();
    static int GetConfig(const std::string& name);

private:
    std::map<std::string, int> data;
};

// config.cpp
#include "config.h"

static Config g_instance;

void Config::Initialize()
{
    g_instance.data["one"] = 1;
    g_instance.data["two"] = 2;
}

int Config::GetConfig(const std::string& name)
{
    return g_instance.data[name];
}

// device.h
#pragma once

#ifdef _DLL
#define dll_cruft __declspec( dllexport )
#else
#define dll_cruft __declspec( dllimport )
#endif

class dll_cruft Device
{
public:
    void Work();
};

// device.cpp
#include "device.h"
#include <iostream>
#include "config.h"

void Device::Work()
{
    std::cout << "Device is working: two = " << Config::GetConfig("two") << '\n';
}

// main.cpp
#include <iostream>
#include "config.h"
#include "device.h"

int main()
{
    std::cout << "Before initialization in application: one = " << Config::GetConfig("one") << '\n';
    Config::Initialize();
    std::cout << "After initialization in application: one = " << Config::GetConfig("one") << '\n';
    Device().Work();
    std::cout << "After working in application: two = " << Config::GetConfig("two") << '\n';
}

输出:

在应用程序初始化之前:一 = 0

在应用程序中初始化后:一 = 1

设备正在工作:两个 = 0

在应用程序中工作后:2 = 2

关于代码的作用和原因的一些解释:

  1. 主应用程序启动
  2. 第一次打印只是为了表明单例尚未初始化
  3. 主应用程序初始化单例
  4. 第一个打印显示初始化工作
  5. 主应用程序启动“硬件设备”
  6. 在 DLL 内部,未初始化单例!我希望它输出two = 2
  7. 最后打印显示单例仍在主应用程序中初始化
4

3 回答 3

2

您可以决定单例应该驻留在哪里,然后将其公开给其他消费者。


由OP编辑:

例如,我希望config实例只出现在 EXE(而不是 DLL)中。

  1. 将实例变成指针

    static Config* g_instance;
    
  2. device为的导出函数添加一个单独的初始化函数:

    void InitializeWithExisting(Config* instance) {g_instance=instance;}
    
  3. 正常初始化单例后,使用第二次初始化:

    Config::Initialize();
    Config::InitializeWithExisting();
    
于 2012-05-09T21:37:05.003 回答
2

当我遇到同样的问题时,我通过创建另一个 DLL 来解决它,该 DLL 的唯一目的是管理单例实例。所有获取指向单例的指针的尝试都会调用这个新 DLL 中的函数。

于 2012-05-09T17:18:19.777 回答
-2

我相信以这种方式定义和访问单例实例可能会解决您的问题:

Config& getInstance()
{
  static Config config;
  return config;
}

这样你也不需要拥有(和调用) Initialize 方法,你可以使用构造函数进行初始化,当你第一次调用 getInstance 时会自动调用它。

于 2012-05-09T17:13:55.753 回答