我有一个包含3个项目的应用程序(在MS Visual Studio中):
main
功能的那个)所以依赖图是:
config 项目包含一个Singleton,它包含一些配置参数。
我决定将设备项目变成DLL。当我这样做时,似乎我在 config 项目中有两个Singleton实例!我想这是一个经典问题,可能有一个很好的解决方案。那么我该如何解决这个问题?
我用以下(相对较小的)代码重现了这个问题。当然,在我的情况下,有大约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';
}
输出:
在应用程序初始化之前:one = 0
在应用程序中初始化后:one = 1
设备正在运行:两个= 0
在申请中工作:两个= 2
关于代码的作用和原因的一些解释:
two = 2
答案 0 :(得分:2)
当我遇到同样的问题时,我通过创建另一个DLL来解决它,其唯一目的是管理单例实例。获取指向单例的指针的所有尝试都会调用此新DLL中的函数。
答案 1 :(得分:2)
您可以决定单身人士应该居住的位置,然后将其暴露给其他消费者。
由OP编辑:
例如,我希望config
实例仅出现在EXE(不是DLL)中。
将实例转换为指针
static Config* g_instance;
为device
的导出函数添加单独的初始化函数:
void InitializeWithExisting(Config* instance) {g_instance=instance;}
正常初始化单例后,使用第二次初始化:
Config::Initialize();
Config::InitializeWithExisting();
答案 2 :(得分:-2)
我相信以这种方式定义和访问单例实例可能会解决您的问题:
Config& getInstance()
{
static Config config;
return config;
}
这样你也不需要(并调用)Initialize方法,你可以使用构造函数进行初始化,这将在你第一次调用getInstance时自动调用。