我目前在某些插件项目中使用dlopen
函数。
此函数句柄返回一个void*
,然后将所有句柄保存到名为handles
的映射中:
void* handle = dlopen(path.c_str(), RTLD_LAZY);
handles[file] = handle;
我的目标是将所有权传递给地图,我当时想到的是unique_ptr
,但不确定是否可行。
如果不可能,我还有什么其他选择?
答案 0 :(得分:6)
如果我理解正确,您可以做类似的事情
定义关闭函数和指针类型的别名:
auto closeFunc = [](void* vp) {
dlclose(vp);
};
using HandlePtr = std::unique_ptr<void, decltype(closeFunc)>;
std::map<std::string, HandlePtr> handles;
然后创建控点并添加到地图:
void* handle = dlopen(path.c_str(), RTLD_LAZY);
HandlePtr ptr( handle, closeFunc );
handles[file] = std::move( ptr );
然后,当唯一的ptr超出范围时,将调用closeFunc
可以通过组合以上两行来防止原始指针:
HandlePtr handle(dlopen(path.c_str(), RTLD_LAZY), closeFunc );
handles[file] = std::move( handle );
这利用std::unique_ptr的第二个参数来指定要使用的删除程序。
PS:map
和unique_ptr
的运行状况不佳,根据您使用的C ++标准,您可能需要一些安置或移动。或改用shared_ptr
。
答案 1 :(得分:1)
std::unique_ptr
对于“包装”使用资源进行操作而不需要在完成时删除或关闭的c库特别有用。它不仅使您忘记了什么时候删除/关闭资源,而且还使使用资源异常安全,因为在发生异常时可以正确清理资源。
我可能会做这样的事情:
// closer function to clean up the resource
struct dl_closer{ void operator()(void* dl) const { dlclose(dl); }};
// type alias so you don't forget to include the closer functor
using unique_dl_ptr = std::unique_ptr<void, dl_closer>;
// helper function that ensures you get a valid dl handle
// or an exception.
unique_dl_ptr make_unique_dl(std::string const& file_name)
{
auto ptr = unique_dl_ptr(dlopen(file_name.c_str(), RTLD_LAZY));
if(!ptr)
throw std::runtime_error(dlerror());
return ptr;
}
并像这样使用它:
// open a dl
auto dl_ptr = make_unique_dl("/path/to/my/plugin/library.so");
// now set your symbols using POSIX recommended casting gymnastics
void (*my_function_name)();
if(!(*(void**)&my_function_name = dlsym(dl_ptr.get(), "my_function_name")))
throw std::runtime_error(dlerror());
答案 2 :(得分:0)
即使TheBadger的答案是最好的选择。请记住,C ++中没有所有权的概念,C ++提供了一些类来模拟这一点并很好地利用RAII,但是即使使用unique_ptr,您也无法真正保证语言对资源的所有权,例如:
javaScriptEnabled
您甚至在unique_ptr类中都有一个get成员函数,使您有机会像使用原始指针那样弄乱内存。
在C ++中,没有机制可以在编译时检测到“所有权”冲突,也许您可以在那里找到一些工具来检查它,但它不在标准之列,而只是推荐做法的问题。
因此,谈论C ++中的“托管”内存而不是“所有权”更为恰当和精确。