HDF5函数和智能析构函数 - std :: unique_ptr()

时间:2016-10-29 23:43:08

标签: c++ smart-pointers hdf5 hdf

许多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); });

由于第二个参数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对象。

有解决方法吗?我想我现在可以写自己的类了(我可以使用std :: function来回答我的第一个问题),但如果我可以使用std::unique_ptr那就很棒。

3 个答案:

答案 0 :(得分: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 :(得分: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>;

答案 2 :(得分:0)

我创建了自己的处理程序类......事实证明它并不那么困难:

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()的原因。