Instead of holding raw pointers, hold some other lightweight reference to the resource. A shared_ptr
and corresponding weak_ptr
instances are one such mechanism, but you can easily implement your own if you don't have access to those types (or their earlier Boost equivalents) or there are other reasons why those types would not be appropriate for your scenario (such as being too heavyweight).
This kind of 'handle' system can be as simple as handing out integers which refer to internal slots in the resource system, which can then be used to dynamically reload a resource if access to it is requested while it's been unloaded.
In practice you probably want something a little more robust, at least a way to treat the handle "like" a pointer and provide operator ->
overloads, for example, by wrapping it in a Handle
type. That
Handle
type can just contain a pointer to a "control block" stored within the resource manager. The control block has the raw resource reference and a boolean flag that indicates if the resource is alive or not, and some kind of key that can be used to reload the resource if needed (I assume a string in the example below). A very simple example of this might look like:
template <typename Resource>
struct Handle {
Resource * operator -> () }
return m_owner->retrieve_resource(m_resource_id);
}
private:
int m_resource_id;
resource_manager * m_owner;
};
namespace detail {
struct control_block {
Resource * resource;
bool is_alive;
std::string key;
};
};
struct resource_manager {
Resource * retrieve_resource (int id) {
auto block = m_resources[id];
if (block->is_alive) {
return block->resource;
} else {
block->resource = reload_resource(key);
block->is_alive = true;
return block->resource;
}
}
private:
std::vector<detail::control_block> m_resources;
};
In this implementation, the resource manager just stores a flat array of control blocks which can be referenced by an integer, and provides a method to recover a resource pointer by ID, reloading that resource if needed. The Handle
class is just a useful wrapper around that behavior. Obviously this is a very simple example, though. If you want something more complete, consider Scott Bilas' article on a generic handle-based resource manager. It takes a somewhat different approach, but is well worth the read.
(Be warned that a need your question implies may mean your resource utilization is very chaotic in nature, and that isn't necessarily a good thing for performance, so you might want to consider that.)