【问题标题】:Factory function returning unique_ptr with custom deleter使用自定义删除器返回 unique_ptr 的工厂函数
【发布时间】:2018-01-03 19:42:02
【问题描述】:

我正在制作一个辅助函数来加载共享库并将结果放入带有自定义删除器的std::unique_ptr(这是模块破坏函数)。

当我没有设置自定义删除器时,这很好用,但是一旦我添加它们,我就会收到一条错误消息,指出无法推断自定义删除器的类型(这是公平的)。

问题是,如果我在调用函数时在哪里指定删除器类型,它最终会看起来很丑。

问题是,我的函数如何自动推断自定义删除器的类型?我应该如何声明 std::vector 的结果 std::unique_ptrs ?

我的代码(我也愿意对代码提出任何建议):

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;
}

【问题讨论】:

  • 为什么destroy 返回一个T*
  • 我猜我复制和粘贴创建部分有点太快了,编辑它;)
  • T 究竟在这里玩什么?似乎 T 应该只是 void 而这根本不需要是模板?

标签: c++ c++14 unique-ptr


【解决方案1】:

编写删除器类型和工厂。

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 符号加载库,它可能做得更好。

【讨论】:

  • 因此,如果我要创建生成的 unique_ptr 的向量,我是否应该像 std::vector&lt;std::unique_ptr&lt; api::Module, lib_unloader &gt;&gt; 那样在模板定义中包含“lib_unloader”?
  • 关于泄漏句柄,是否也将其包装在 unique_ptr 中,以便在超出范围时自行删除是个好主意?
  • @ThéoChampion 是的,这就是你的独特 ptr 的类型。对于手柄,我会写一个更好的。它可能包含unique_ptr。我草拟了一个解决方案,我没有把它变成一个对象,只是一个unique_ptr
  • 我注意到在上面的代码中,get_sym 返回一个T *(**)() 是否正常?我认为这会在最后调用 ptr_deleter 时导致段错误
  • @thro 已修复,不测试的价格。 ;)
猜你喜欢
  • 1970-01-01
  • 2015-08-15
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 2017-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多