使用自定义删除器返回 unique_ptr 的工厂函数
Factory function returning unique_ptr with custom deleter
我正在制作一个辅助函数,用于加载共享库并将结果放入带有自定义删除器(即模块销毁函数)的 std::unique_ptr
中。
当我没有设置自定义删除器时,这工作正常,但一旦我添加它们,我就收到一条错误消息,提示无法推断自定义删除器的类型(这很公平)。
问题是,如果我在调用该函数时在哪里指定删除器类型,它最终看起来会非常难看。
问题是,我的函数如何自动推断出自定义删除器的类型?我应该如何声明结果 std::unique_ptr
的 std::vector
?
我的代码(我也愿意接受任何关于代码的建议):
template <typename T, typename D>
std::unique_ptr<T, D> openLib(const std::string &lib_path,
const std::string &csym = "create",
const std::string &dsym = "destroy")
{
void *handle;
if (!(handle = dlopen(lib_path.c_str(), RTLD_LAZY)))
{
std::cerr << "dlopen " << dlerror() << std::endl;
return nullptr;
}
T *(*create)();
if (!(create = (T * (*)()) dlsym(handle, csym.c_str())))
{
std::cerr << "dlsym " << csym << dlerror() << std::endl;
return nullptr;
}
void (*destroy)();
if (!(destroy = (void (*)()) dlsym(handle, dsym.c_str())))
{
std::cerr << "dlsym " << dsym << dlerror() << std::endl;
return nullptr;
}
auto cDel = [destroy](T *lib) { destroy(); };
std::unique_ptr<T, decltype(cDel)> lib_ptr((T *)create(), cDel);
return lib_ptr;
}
写一个删除器类型和工厂。
using deleter = void();
using ptr_deleter = deleter*;
struct lib_unloader {
deleter* del = 0;
void operator()(void*)const { if (del) del(); }
explicit operator bool() const { return del; }
};
lib_unloader get_lib_unloader( void* handle, char const* destroy_name ) {
auto del = ptr_deleter( dlsym( handle, destroy_name ) );
return {del};
}
template<class T>
using lib_up = std::unique_ptr< T, lib_unloader >;
template<class T>>
lib_up<T> openLib(const std::string &lib_path,
const std::string &csym = "create",
const std::string &dsym = "destroy")
{
void *handle;
if (!(handle = dlopen(lib_path.c_str(), RTLD_LAZY)))
{
std::cerr << "dlopen " << dlerror() << std::endl;
return nullptr;
}
T *(*create)();
if (!(create = (T * (*)()) dlsym(handle, csym.c_str())))
{
std::cerr << "dlsym " << csym << dlerror() << std::endl;
return nullptr;
}
auto destroy = get_lib_unloader( handle, dsym.c_str() );
if (!destroy) {
std::cerr << "dlsym " << dsym << dlerror() << std::endl;
return nullptr;
}
return {create(), destroy};
}
我自己,我会写一个更好的句柄。请注意,您的代码疯狂地泄漏了动态库句柄。
using libhandle_ptr = std::unique_ptr<void, std::integral_constant<int(*)(void*), dlclose>>;
libhandle_ptr make_libhandle(const char* filename, int flags) {
return libhandle_ptr( dlopen(filename, flags) );
}
template<class T>
T* get_sym( libhandle_ptr const& handle, const char* symbol ) {
if (!handle || !symbol) return nullptr;
return static_cast<T*>( dlsym( handle.get(), symbol ) );
}
现在我们得到:
lib_unloader get_lib_unloader( libhandle const& handle, char const* destroy_name ) {
auto del = get_sym<deleter>( handle, destroy_name );
return {del};
}
template<class T>>
lib_up<T> openLib( libhandle_ptr const& handle,
const char* csym = "create",
const char* dsym = "destroy")
{
if (!handle)
return {};
auto create = get_sym<T*()>( handle, csym );
if (!create)
{
std::cerr << "dlsym " << csym << dlerror() << std::endl;
return {};
}
auto destroy = get_lib_unloader( handle, dsym.c_str() );
if (!destroy) {
std::cerr << "dlsym " << dsym << dlerror() << std::endl;
return {};
}
return {create(), destroy};
}
希望用户在需要符号时提供 libhandle_ptr
。
请注意,boost 有一个 dll 符号加载库,它可能做得更好。
我正在制作一个辅助函数,用于加载共享库并将结果放入带有自定义删除器(即模块销毁函数)的 std::unique_ptr
中。
当我没有设置自定义删除器时,这工作正常,但一旦我添加它们,我就收到一条错误消息,提示无法推断自定义删除器的类型(这很公平)。
问题是,如果我在调用该函数时在哪里指定删除器类型,它最终看起来会非常难看。
问题是,我的函数如何自动推断出自定义删除器的类型?我应该如何声明结果 std::unique_ptr
的 std::vector
?
我的代码(我也愿意接受任何关于代码的建议):
template <typename T, typename D>
std::unique_ptr<T, D> openLib(const std::string &lib_path,
const std::string &csym = "create",
const std::string &dsym = "destroy")
{
void *handle;
if (!(handle = dlopen(lib_path.c_str(), RTLD_LAZY)))
{
std::cerr << "dlopen " << dlerror() << std::endl;
return nullptr;
}
T *(*create)();
if (!(create = (T * (*)()) dlsym(handle, csym.c_str())))
{
std::cerr << "dlsym " << csym << dlerror() << std::endl;
return nullptr;
}
void (*destroy)();
if (!(destroy = (void (*)()) dlsym(handle, dsym.c_str())))
{
std::cerr << "dlsym " << dsym << dlerror() << std::endl;
return nullptr;
}
auto cDel = [destroy](T *lib) { destroy(); };
std::unique_ptr<T, decltype(cDel)> lib_ptr((T *)create(), cDel);
return lib_ptr;
}
写一个删除器类型和工厂。
using deleter = void();
using ptr_deleter = deleter*;
struct lib_unloader {
deleter* del = 0;
void operator()(void*)const { if (del) del(); }
explicit operator bool() const { return del; }
};
lib_unloader get_lib_unloader( void* handle, char const* destroy_name ) {
auto del = ptr_deleter( dlsym( handle, destroy_name ) );
return {del};
}
template<class T>
using lib_up = std::unique_ptr< T, lib_unloader >;
template<class T>>
lib_up<T> openLib(const std::string &lib_path,
const std::string &csym = "create",
const std::string &dsym = "destroy")
{
void *handle;
if (!(handle = dlopen(lib_path.c_str(), RTLD_LAZY)))
{
std::cerr << "dlopen " << dlerror() << std::endl;
return nullptr;
}
T *(*create)();
if (!(create = (T * (*)()) dlsym(handle, csym.c_str())))
{
std::cerr << "dlsym " << csym << dlerror() << std::endl;
return nullptr;
}
auto destroy = get_lib_unloader( handle, dsym.c_str() );
if (!destroy) {
std::cerr << "dlsym " << dsym << dlerror() << std::endl;
return nullptr;
}
return {create(), destroy};
}
我自己,我会写一个更好的句柄。请注意,您的代码疯狂地泄漏了动态库句柄。
using libhandle_ptr = std::unique_ptr<void, std::integral_constant<int(*)(void*), dlclose>>;
libhandle_ptr make_libhandle(const char* filename, int flags) {
return libhandle_ptr( dlopen(filename, flags) );
}
template<class T>
T* get_sym( libhandle_ptr const& handle, const char* symbol ) {
if (!handle || !symbol) return nullptr;
return static_cast<T*>( dlsym( handle.get(), symbol ) );
}
现在我们得到:
lib_unloader get_lib_unloader( libhandle const& handle, char const* destroy_name ) {
auto del = get_sym<deleter>( handle, destroy_name );
return {del};
}
template<class T>>
lib_up<T> openLib( libhandle_ptr const& handle,
const char* csym = "create",
const char* dsym = "destroy")
{
if (!handle)
return {};
auto create = get_sym<T*()>( handle, csym );
if (!create)
{
std::cerr << "dlsym " << csym << dlerror() << std::endl;
return {};
}
auto destroy = get_lib_unloader( handle, dsym.c_str() );
if (!destroy) {
std::cerr << "dlsym " << dsym << dlerror() << std::endl;
return {};
}
return {create(), destroy};
}
希望用户在需要符号时提供 libhandle_ptr
。
请注意,boost 有一个 dll 符号加载库,它可能做得更好。