diff --git a/include/class_loader/multi_library_class_loader.hpp b/include/class_loader/multi_library_class_loader.hpp
index a8ea70e..ec4b51a 100644
--- a/include/class_loader/multi_library_class_loader.hpp
+++ b/include/class_loader/multi_library_class_loader.hpp
@@ -111,7 +111,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader
"was explicitly loaded through MultiLibraryClassLoader::loadLibrary()");
}
- return loader->createInstance(class_name, std::forward(args)...);
+ return keepLoaderAlive(
+ loader, loader->createInstance(class_name, std::forward(args)...));
}
/**
@@ -137,7 +138,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader
"MultiLibraryClassLoader bound to library " + library_path +
" Ensure you called MultiLibraryClassLoader::loadLibrary()");
}
- return loader->createInstance(class_name, std::forward(args)...);
+ return keepLoaderAlive(
+ loader, loader->createInstance(class_name, std::forward(args)...));
}
/// Creates an instance of an object of given class name with ancestor class Base
@@ -167,7 +169,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader
"Make sure that the library exists and was explicitly loaded through "
"MultiLibraryClassLoader::loadLibrary()");
}
- return loader->createUniqueInstance(class_name, std::forward(args)...);
+ return keepLoaderAlive(
+ loader, loader->createUniqueInstance(class_name, std::forward(args)...));
}
/// Creates an instance of an object of given class name with ancestor class Base
@@ -195,7 +198,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader
"MultiLibraryClassLoader bound to library " + library_path +
" Ensure you called MultiLibraryClassLoader::loadLibrary()");
}
- return loader->createUniqueInstance(class_name, std::forward(args)...);
+ return keepLoaderAlive(
+ loader, loader->createUniqueInstance(class_name, std::forward(args)...));
}
/**
@@ -333,6 +337,35 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader
int unloadLibrary(const std::string & library_path);
private:
+ std::shared_ptr getSharedClassLoader(const ClassLoader * loader) const;
+
+ /// Makes the instance keep its ClassLoader alive, so it may outlive this MultiLibraryClassLoader.
+ template
+ std::shared_ptr keepLoaderAlive(const ClassLoader * loader, std::shared_ptr obj) const
+ {
+ struct Holder // Members are destroyed in reverse order: the instance before its loader.
+ {
+ std::shared_ptr loader;
+ std::shared_ptr obj;
+ };
+ auto holder = std::make_shared(Holder{getSharedClassLoader(loader), std::move(obj)});
+ return std::shared_ptr(holder, holder->obj.get());
+ }
+
+ /// Makes the instance keep its ClassLoader alive, so it may outlive this MultiLibraryClassLoader.
+ template
+ ClassLoader::UniquePtr keepLoaderAlive(
+ const ClassLoader * loader, ClassLoader::UniquePtr obj) const
+ {
+ auto deleter = obj.get_deleter();
+ return ClassLoader::UniquePtr(
+ obj.release(),
+ [deleter = std::move(deleter), keep_alive = getSharedClassLoader(loader)](Base * p) mutable {
+ deleter(p);
+ keep_alive.reset(); // unique_ptr::reset() keeps the deleter alive, so release here.
+ });
+ }
+
/**
* @brief Indicates if on-demand (lazy) load/unload is enabled so libraries are loaded/unloaded
*
diff --git a/src/multi_library_class_loader.cpp b/src/multi_library_class_loader.cpp
index 36f4aa0..5316596 100644
--- a/src/multi_library_class_loader.cpp
+++ b/src/multi_library_class_loader.cpp
@@ -31,55 +31,21 @@
#include
#include
+#include