I've seen many variants of this question asked here, but I still feel my specific case is different.
My goal is wrapping a C API that looks like this:
TF_Buffer* buf = TF_AllocateBuffer();
// ...
TF_DeleteBuffer(buf);
Since I have many of these objects, I'd love to create a generic type named handle
that could hold a given pointer and call the appropriate deallocator upon destruction. My imagined use case would be
class buffer : public handle<TF_Buffer, TF_DeleteBuffer> {
public:
buffer(TF_Buffer* b): handle(b) {}
}
unfortunately I'm unable to get this to work since TF_DeleteBuffer
is a simple function (of type void TF_DeleteBuffer(TF_Buffer*)
). I did manage to work around the issue with creating a function object for the function, so the following does work
template<typename Obj, typename Deleter>
class handle {
public:
Obj* obj;
handle(Obj* o): obj(o) {};
~handle() { if (obj) Deleter()(obj); }
};
struct buffer_deleter {
void operator()(TF_Buffer* b) { TF_DeleteBuffer(b); }
};
class buffer : public handle<TF_Buffer, buffer_deleter> {
public:
buffer(TF_Buffer* b): handle(b) {}
}
but it feels dirty having to define the buffer_deleter
class just for this purpose. I'd imagine something like this ought to work (with or without the std::function
)
template<typename Obj, std::function<void(Obj*)> Deleter>
class handle {
// ...
}
but I can't find a way to make the compiler happy. From what I understand, this is somewhat similar to std::unique_ptr
which accepts a deleter type object, vs std::shared_ptr
which accepts a deleter function pointer and stores it in the shared object. I don't mind storing the pointer explicitly (and using extra memory), but at the same time, given I'll be creating lots of these types, I'd like to have some way of making it syntactically nice. I really do not want to pass the deleter pointer to each instance of the object being created, which is why I'm trying to hide it in the template.
You can define a non-type template parameter as function pointer.
template<typename Obj, void(*Deleter)(Obj*)>
class handle {
public:
Obj* obj;
handle(Obj* o): obj(o) {};
~handle() { if (obj) Deleter(obj); }
};
And use it like
class buffer : public handle<TF_Buffer, &TF_DeleteBuffer> {
...
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With