我正在开发一个项目,该项目应该能够在运行时通过dlopen
加载动态链接的库。
核心框架已经完成,它确实正在运行,但我对如何正确管理库在堆上分配的对象有一些疑问。库的接口只有一个方法,它返回指向库内静态分配的对象的指针,该库是具有virtual
方法的公共类的子类型
为了更好地解释它,我将提供一个关于我希望它如何工作的存根:
// header common to the core and to the libraries
class BaseSetting {
..
}
class DerivedSetting1 : public BaseSetting { .. }
class DerivedSetting2 : public BaseSetting { .. }
class ObjectInterface {
private:
vector<BaseSetting*> settings;
protected:
void registerSetting(Setting *setting) { settings.push_back(setting); }
public:
vector<Setting*> *getSettings() { return &settings; }
}
// library example
class ConcreteObject {
ConcreteObject() {
registerSetting(new ..);
registerSetting(new ..);
}
static ConcreteObject object;
extern "C" ConcreteObject *retrieve() { return &object; }
这里的主要问题是我应该如何管理库的堆分配设置?我需要多态性,所以我不能只在向量中存储具体对象,同时我需要在需要时通过用dlclose
卸载当前来切换库,并释放与它们相关的所有内存。我可以使用unique_ptr
,但这会使事情变得复杂,因为我只能通过get()
获取原始指针来从核心使用它们,这会破坏任何所有权。
是否有一种常见的设计模式来处理这种情况?
答案 0 :(得分:1)
解决方案与动态链接并不真正相关 - 无论您的对象来自共享库还是作为主类应用程序的一部分来自基类的派生类,问题及其解决方案都是相同的。动态库唯一的“额外”问题是你显然不能使用dlclose
同时仍然拥有由驻留在动态库中的代码创建的活动对象(除非你100%确定NOTHING会调用任何代码在DL中,当然)。
你的ObjectInterface需要有一个析构函数来删除settings
中的元素,
或者,您需要在适当的地方调用unregisterSetting
(例如某些析构函数)。
答案 1 :(得分:0)
查看this的附件。 module.cc
和client.cc
是动态加载到共享上下文中并相互协作的外部对象,app.cc
是相关的魔术,使其看起来C++
。它们的构造/破坏方式是您认为适合您的问题的方法。
本质上,每个可插入类型都应该从公共接口bootstrap_ifc
继承,并且有两个方法可以从共享库中获得已知接口。
extern "C" bootstrap_ifc* client_constructor()
{
return new(std::nothrow) client;
}
extern "C" void client_destructor(bootstrap_ifc* obj)
{
delete obj;
}
答案 2 :(得分:-1)
您可以编写代表您的库的单例(您可以使用singulatiry库)。在这个包装器的构造函数中,您将调用dlopen并在析构函数dlclose中删除所有已分配的对象。 或者你想要更简单的东西 - 只需实现函数init和destroy并按正确的顺序调用它们: dlopen - &gt; init - &gt;使用图书馆 - &gt;销毁 - &gt; dlclose