I'm using RAII to manage resources in my code by making use of std::unique_ptr
with custom deleters. So far this has been relatively trivial, but I now want to add an RAII-wrapper for a resource which requires access to an existing managed resource as part of its cleanup functor.
To break it down, I have one class which has an RAII-managed resource and can acquire additional resources which depend on it:
struct CloseHandleFunctor
{
typedef HANDLE pointer;
void operator()(const HANDLE h)
{
::CloseHandle(h);
}
};
using AutoHandle = std::unique_ptr<HANDLE, CloseHandleFunctor>;
class Helper
{
public:
// acquires a resource associated with h_
Resource get_resource();
// releases the resource acquired by get_resource()
void release_resource(const Resource res);
// ...
private:
AutoHandle h_;
};
I want to wrap the Resource
returned by Helper::get_resource()
, but can't work out how to use std::unique_ptr
to provide access to the instance of the Helper
class within the functor:
struct ReleaseResourceFunctor
{
typedef Resource pointer;
void operator()(Helper h, const Resource r)
{
h.release_resource(r);
}
};
using AutoResource = std::unique_ptr<Resource, ReleaseResourceFunctor>;
// no way to pass the instance of Helper ~~~^
This is how I would like to use it:
int main()
{
Helper h;
{
AutoResource res(h.get_resource());
}
// h.release_resource() gets called
}
As suggested by Joachim and Casey, I can get it working by storing a pointer to the instance of the Helper
class in the functor:
struct ReleaseResourceFunctor
{
typedef Resource pointer;
Helper *helper_;
ReleaseResourceFunctor()
: helper_(nullptr)
{
}
void setHelper(Helper * const h)
{
helper_ = h;
}
void operator()(const Resource r)
{
if (helper_ != nullptr)
{
helper_->release_resource(r);
}
}
};
...and then by assigning the helper instance after constructing the std::unique_ptr
:
int main()
{
Helper h;
{
AutoResource res(h.get_resource());
res.get_deleter().setHelper(&h);
}
// h.release_resource() gets called as expected
}
It seems a little fragile (remembering to assign the helper instance each time), but it does work as expected.