I had the idea to use std::unique_ptr
as a base class for another class that manages some kind of external resource.
Let's assume my program needs to manage resources provided by a C-like library via the following functions: R* lib_create_resource(A* allocator);
and void lib_destroy_resource(R* resource, A* allocator);
. I would like to create a class that manages this resource, so I thought that using std::unique_ptr
as a base class would be a good idea. Here's a pseudo-implementation:
struct Resource: public std::unique_ptr<R, std::function<void(R*)>> {
Resource():
unique_ptr{
lib_create_resource(&my_allocator),
[this](R* r) { lib_destroy_resource(r, &my_allocator); }
}
{ }
/* Other functions that manipulate the resource */
private:
A my_allocator;
};
- Why am I using
std::unique_ptr
as a base class rather than as a non-static member? Because I would like to exposestd::unique_ptr
's methods, such asget()
,reset()
,operator bool()
, etc., and this way I don't need to manually re-define each of them, especially when the library provides many kinds of different resources instead of just one, and I want to write a separate wrapper for each of them. - Why not use
std::unique_ptr<R, std::function<void(R*)>>
on its own then, without theResource
class? Because I would like to extendstd::unique_ptr
and provide additional methods, specific to this type of resource.
Now, the above pseudo-implementation has two major problems, which are the main point of my question.
- Since base classes are initialised before non-static members,
my_allocator
is passed tolib_create_resource()
uninitialised. This isn't hard to fix, as I can just default-initialise theunique_ptr
base and re-assign it in the constructor's body, but I think it's easy to forget about this. - Similarly, during destruction, the non-static members are destroyed before the base classes. First,
my_allocator
will be destroyed, then~unique_ptr()
will be called, which in turn will calllib_destroy_resource()
withmy_allocator
. But at that point,my_allocator
no longer exists.
I haven't been able to come up with any solution for issue number 2. Is there a way to re-design this class so that lib_destroy_resource()
doesn't access my_allocator
outside its lifetime? Of course, one solution would be to manually call lib_destroy_resource()
or std::unique_ptr::reset()
at the appropriate times, but automatic resource management with RAII is considered good practice, especially when exceptions are involved. So is there a better way to accomplish this, possibly by implementing my own std::unique_ptr
-like class?
Aucun commentaire:
Enregistrer un commentaire