是否可以将所有权从void *转移到unique_ptr?

时间:2019-05-23 07:54:44

标签: c++ c++11

我目前在某些插件项目中使用dlopen函数。
此函数句柄返回一个void*,然后将所有句柄保存到名为handles的映射中:

void* handle = dlopen(path.c_str(), RTLD_LAZY);  
handles[file] = handle;

我的目标是将所有权传递给地图,我当时想到的是unique_ptr,但不确定是否可行。

如果不可能,我还有什么其他选择?

3 个答案:

答案 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:mapunique_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 ++中的“托管”内存而不是“所有权”更为恰当和精确。