Функции HDF5 и интеллектуальные деструкторы — std :: unique_ptr ()

Многие функции HDF5 инициализируются следующим образом

hid_t handler = DoSomething(someHandler);

И нужно вручную освободить память, зарезервированную такой операцией, используя что-то вроде:

freeme(handler);

Так что это тот же самый кошмар / проблемы, которые возникают при использовании malloc и / или new оператор.

Я хочу создать что-то вроде unique_ptr справиться с этим при разрушении. Проблема, однако, в том, что каждая функция имеет свою функцию освобождения.

Например:

hid_t attribType = H5Aget_type(attribHandler);

должен быть освобожден с

H5Tclose(attribType);

Но эта функция

attribHandler = H5Aopen(obj_id,"name",H5P_DEFAULT);

Должен быть освобожден с

H5Aclose(attribHandler);

Поэтому мне нужно написать класс, который может принять hid_t в качестве параметра шаблона (это легко), а также может принимать функцию освобождения в качестве некоторого параметра и вызывать его при уничтожении.

Какой лучший способ достичь этого?


Обновить

Мне было предложено использовать std::unique_ptr с пользовательским удалителем, но это не работает, потому что std::unique_ptr ожидает указатель.

std::unique_ptr<hid_t,std::function<herr_t(hid_t)>> attribType(H5Aget_type(attribHandler), [](hid_t f) { return H5Tclose(f); });

Это создает ошибку компиляции из-за второго параметра, лямбда-функции. Ошибка говорит (g ++ 4.9):

error: invalid conversion from ‘hid_t {aka int}’ to ‘std::unique_ptr<int, std::function<int(int)> >::pointer {aka int*}’ [-fpermissive]
std::unique_ptr<hid_t,std::function<herr_t(hid_t)>> attribType(H5Aget_type(attribHandler), [](hid_t f) { return H5Tclose(f); });
^

Ошибка происходит потому, что std::unique_ptr ожидает держать указатель на hid_tне hid_t объект.

Это можно обойти? Я думаю, что могу написать свой собственный класс, который делает это сейчас (я могу использовать std :: function для ответа на мой первый вопрос), но было бы здорово, если бы я мог использовать std::unique_ptr,

1

Решение

Возможно, что-то в этом роде:

struct MyDeleter {
typedef hid_t pointer;
typedef void (*FreeFunc)(hid_t);
FreeFunc free_func_;

MyDeleter(FreeFunc free_func) : free_func_(free_func) {}
void operator()(hid_t f) const { free_func_(f); }
};

std::unique_ptr<hid_t, MyDeleter> p(
H5Aget_type(attribHandler),
MyDeleter(H5Tclose));
1

Другие решения

Вы можете использовать что-то вроде:

template <typename Factory, Factory factory,
typename Deleter, Deleter deleter>
class SmartHandleH5;

template <typename Ret, typename ... Ts, Ret (*factory)(Ts...),
void (*deleter)(Ret)>
class SmartHandleH5<Ret (*)(Ts...), factory, void (*)(Ret), deleter>
{
public:
template <typename ... Us>
SmartHandle(Us&&... args) : handler(factory(std::forward<Us>(args)...)) {}

// Not copyable
SmartHandle(const SmartHandle&) = delete;
SmartHandle& operator =(const SmartHandle&) = delete;

// Not movable
SmartHandle(SmartHandle&&) = delete;
SmartHandle& operator =(SmartHandle&&) = delete;

// To avoid strange case with our template constructor
SmartHandle(SmartHandle&) = delete;
SmartHandle(const SmartHandle&&) = delete;

~SmartHandle() { deleter(handler); }

const T& get() const { return handler; }
T& get() { return handler; }

private:
Ret handler;
};

А затем используйте фабрику / деструктор отображения один раз:

using SmartHandlerGetType = SmartHandlerH5<decltype(&H5Aget_type), H5Aget_type,
delctype(H5Tclose), H5Tclose>;

using SmartHandlerOpen = SmartHandlerH5<decltype(&H5Aopen), H5Aopen,
delctype(H5Aclose), H5Aclose>;

и использовать это:

SmartHandlerGetType attribType(attribHandler);
SmartHandlerOpen attribHandler(obj_id, "name", H5P_DEFAULT);

Кроме того, вы можете добавить дополнительный слой, чтобы полностью скрыть hid_t

template <typename SmartHandle>
class HidHandle : private SmartHandle
{
public:
using SmartHandle::SmartHandle;

void foo() { someFunctionUsingHid(get()); }
};

а также

using HidHandleGetType = HidHandle<SmartHandlerGetType>;
using HidHandleOpen = HidHandle<SmartHandlerOpen>;
1

Я создал свой собственный класс обработчиков … оказалось, что это не так сложно:

template <typename T, typename Deleter>
class SmartHandle
{
public:
typedef T value_type;
typedef Deleter deleter_function;
private:
T _value;
Deleter _deleter;
public:
SmartHandle(T value, Deleter deleter);
~SmartHandle();

T get();
};

template <typename T, typename Deleter>
SmartHandle<T,Deleter>::SmartHandle(T value, Deleter deleter)
{
this->_value   = value;
this->_deleter = deleter;
}

template <typename T, typename Deleter>
T SmartHandle<T,Deleter>::get()
{
return _value;
}

template <typename T, typename Deleter>
SmartHandle<T,Deleter>::~SmartHandle()
{
_deleter(_value);
}

Чтобы использовать это:

SmartHandle<hid_t,std::function<herr_t(hid_t)>> attribType(H5Aget_type(attribHandler.get()), [](hid_t f) { return H5Tclose(f); });

Вот attribHandler также использует SmartHandleвот почему есть .get() там.

0
По вопросам рекламы [email protected]