I'm working on a project which should be able to load dynamically linked libraries at runtime through dlopen
.
The core framework is finished and it is indeed working but I have some doubt about how to correctly manage objects allocated on the heap by the libraries. The interface to the library has just one method which returns a pointer to an object statically allocated inside the library which is a subtype of a common class with virtual
methods
To explain it better I'll provide a stub of how I want it to work:
// 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; }
The main problem here is how I should manage the heap allocated settings of the library? I need polymorphism so I can't just store concrete objects inside the vector and at the same time I need to switch between libraries when needed, by unloading the current with dlclose
, and release all the memory associated with them. I could use an unique_ptr
but this would complicates things because I'll be able to use them from the core just by getting the raw pointer through get()
which then would break any ownership.
Is there a common design pattern to handle such situations?
The solution isn't really related to dynamic linking - the problem and its solution is the same whether your objects come from a shared library or is part of the main application as derived classes from a base-class. The only "extra" problem with dynamic libraries is that you obviously can't use dlclose
while still having active objects created by code that resides in the dynamic library (unless you are 100% sure NOTHING will call any of the code in the DL, of course).
Your ObjectInterface needs to have a destructor that deletes the elements in settings
,
Alternatively, you will need to have a unregisterSetting
that is called somewhere suitable (eg some destructor).
Have a look at the attachment to this . module.cc
and client.cc
are external objects dynamically loaded into a shared context and collaborating with each other, app.cc
is the associated magic to make it look C++
. The way they are constructed/destructed is what you may find appropriate for your problem.
In essence, each pluggable type is supposed to inherit from a common interface bootstrap_ifc
and have two methods with known interface available from the shared library.
extern "C" bootstrap_ifc* client_constructor()
{
return new(std::nothrow) client;
}
extern "C" void client_destructor(bootstrap_ifc* obj)
{
delete obj;
}
You can write a singleton which represents your library (you may use singulatiry library for that). In constructor of this wrapper you will call dlopen and in destructor dlclose + delete all allocated objects. Or you want something simpler - just implement functions init and destroy and call them in proper order: dlopen -> init -> work with library -> destroy -> dlclose
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.