HDF5 函数和智能析构函数 - std::unique_ptr()
HDF5 Functions and Smart Destructors - std::unique_ptr()
很多HDF5函数初始化如下
hid_t handler = DoSomething(someHandler);
并且必须手动释放此类操作保留的内存,使用类似以下内容:
freeme(handler);
因此,使用 malloc
and/or 和 new
运算符得到的 nightmare/problems 是一样的。
我想创建类似 unique_ptr
的东西来在销毁时处理这个问题。 然而,问题是每个不同的函数都有不同的释放函数。
例如:
hid_t attribType = H5Aget_type(attribHandler);
必须用
释放
H5Tclose(attribType);
但是这个函数
attribHandler = H5Aopen(obj_id,"name",H5P_DEFAULT);
必须用
释放
H5Aclose(attribHandler);
所以我需要写一个 class 可以将 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); });
这会由于第二个参数 lambda 函数而产生编译错误。错误说 (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
对象。
有办法解决这个问题吗?我想我现在可以编写自己的 class 来执行此操作(我可以使用 std::function 来回答我的第一个问题),但如果我可以使用 std::unique_ptr
.[=29= 就更好了]
也许是这样的:
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));
我创建了自己的处理程序class...事实证明这并不难:
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()
。
您可以使用类似的东西:
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;
};
然后使用映射factory/destructor一次:
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>;
很多HDF5函数初始化如下
hid_t handler = DoSomething(someHandler);
并且必须手动释放此类操作保留的内存,使用类似以下内容:
freeme(handler);
因此,使用 malloc
and/or 和 new
运算符得到的 nightmare/problems 是一样的。
我想创建类似 unique_ptr
的东西来在销毁时处理这个问题。 然而,问题是每个不同的函数都有不同的释放函数。
例如:
hid_t attribType = H5Aget_type(attribHandler);
必须用
释放H5Tclose(attribType);
但是这个函数
attribHandler = H5Aopen(obj_id,"name",H5P_DEFAULT);
必须用
释放H5Aclose(attribHandler);
所以我需要写一个 class 可以将 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); });
这会由于第二个参数 lambda 函数而产生编译错误。错误说 (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
对象。
有办法解决这个问题吗?我想我现在可以编写自己的 class 来执行此操作(我可以使用 std::function 来回答我的第一个问题),但如果我可以使用 std::unique_ptr
.[=29= 就更好了]
也许是这样的:
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));
我创建了自己的处理程序class...事实证明这并不难:
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()
。
您可以使用类似的东西:
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;
};
然后使用映射factory/destructor一次:
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>;