Можно ли передать право собственности с void * на unique_ptr? - PullRequest
1 голос
/ 23 мая 2019

В настоящее время я использую функции dlopen для какого-либо проекта плагина.
Этот дескриптор функции возвращает void*, а затем я сохраняю весь дескриптор на карте с именем handles:

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

Моя цель - передать владение картой, я думал о unique_ptr, но не уверен, возможно ли это вообще.

Если это невозможно, какие у меня есть альтернативы?

Ответы [ 3 ]

6 голосов
/ 23 мая 2019

Если я правильно понимаю, вы можете сделать что-то вроде

Определить функцию закрытия и псевдоним для типа указателя:

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

Затем будет вызван closeFunc, когда уникальный ptr выйдет за рамки

Необработанный указатель можно предотвратить путем объединения двух строк выше:

HandlePtr handle(dlopen(path.c_str(), RTLD_LAZY), closeFunc );
handles[file] = std::move( handle );

Здесь используется второй аргумент std :: unique_ptr , который указывает используемый для удаления.

PS: map s и unique_ptr s играют не так, как есть, вам могут понадобиться некоторые движения или движения в зависимости от используемого вами стандарта C ++. Или используйте shared_ptr вместо этого.

1 голос
/ 23 мая 2019

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());
0 голосов
/ 23 мая 2019

Даже если ответ от TheBadger - лучший.Помните, что в C ++ отсутствует понятие владения, C ++ предоставляет классы для имитации этого и эффективного использования RAII, но у вас на самом деле нет никаких гарантий от языка, чтобы гарантировать владение ресурсом, даже с unique_ptr, например:

{
  auto p_i = new int{5};
  auto up_i = std::unique_ptr<int>{p_i};
  *p_i = 6; //nothing in the language prevent something like this
  assert(*up_i == 6); //the unique_ptr ownership is not assured as you can see here
  delete p_i; //still not illegal
} //at run time, RAII mechanism strikes, destroy unique_ptr, try to free an already freed memory, ending up to a core dumped

У вас даже есть функция-член в классе unique_ptr, которая дает вам возможность испортить вашу память, как вы могли бы с необработанными указателями.

В C ++ нет механизма для обнаруженияНарушение "владения" во время компиляции, может быть, вы можете найти какие-то инструменты, чтобы проверить это, но это не в стандарте, а только в вопросе рекомендуемых практик.

Таким образом, более актуально и точно говоритьоб «управляемой» памяти в C ++ вместо «владения».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...