   Resource Management Class Design
  I'm currently developing a resource management system in C++, the purpose of which is to:1) Load a `resource' (an image, sound, model, etc.), usually from file; and2) Provide access to that resource to multiple clients through a `handle'.I'm trying to achieve maximum generality by piecing it together from small, reusable classes, and herein lies the problem. The basic resource class hierarchy is (excuse my ASCII art): Resource_base |Resource_lookup |   Resource |  Image/SoundResource_base implements a simple reference-counting mechanism.Resource_lookup implements a map lookup and allocates new resources when needed.Resource specializes Resource_lookup for a filename and provides some loading functionality.Finally, `Image' and `Sound' provide their own resource-specific functionality, and it is these classes that `Handles' point to.I like this class hierarchy because it lets me tack on other Resource-like objects (textures, for example) without a problem - in theory. The problem lies in the implementation; it's horrible because of the deep layering of templates. The requirement to instantiate (IMHO one of the worst headaches in C++) some of the class templates, and all the syntactic overhead, makes the code completely and utterly disgusting.What do I do?There seems to be only two solutions:1) Persevere with the code I have and continue having sleepless nights trying to come up with a better solution;2) Scrap the whole thing and go with a bunch of fat monolithic classes, thus completely defeating the purpose of using an OO language.There must be a better solution, someone please enlighten me.Cheers.   
  I'm not entirely sure what you mean by instantiate template classes, I'm guessing you mean something like Resource< Image, ImageManager >At the risk of offering too simple and insulting an answer:typedef Resource< Image, ImageManger > ImageHandle;   ;Quote:Original post by BezbenI'm not entirely sure what you mean by instantiate template classes, I'm guessing you mean something like Resource< Image, ImageManager >At the risk of offering too simple and insulting an answer:typedef Resource< Image, ImageManger > ImageHandle;The problem requiring template instantiation is outlined here.My code compiles and runs fine, no problems there. It looks horrible, is very difficult to understand, and just plain doesn't "feel" right.   ;  Oh yes, I know what you mean. Without seeing more of your code, its hard to suggest different ways of doing things. Any chance of posting the headers?What are you using templates to do? I think the layout as suggested could easily be accomplished with standard inheritance?   ;  This is an outline of what i have for a resource manager.It has a lot of templates and casting, but it works for me.Maybe you can draw some inspiration from it. It is a bit different of a layout due to the fact that I let the handles be controled by the resource manager,and not be connected to the actual resource's type but to the base resource type. This requires dynamic casts, but it seems to work ok for now.Resource Manager (handle counting, begins load operations so as to keep only one copy arround)-Base Resource (includes virtual Load/Save/Delete interface)--Sound --Image  - All have their own happy interfaces ontop of the base interface--Model /THEN i deal with handles and resources in the folling way:Sound *s = new Sound;size_t handle = ResMan::Add ( "filename", &s );  // stores S as a base resource or drops the pointer(for garbage collection) and returns a handle specific to that filename....Sound *s;if ( ResMan::Lock ( handle, &s ) ) //Using dynamic_cast to properly convert "base resource" into sound.{ResMan::Unlock ( handle );}I avoided the use of templates and went with derived classes instead. Holding pointers to a parrent class and casting down to the other classes   ;  The common code I have for resources really is just linking handle ids to whatever-the-resource-class-is*. So for me, that part is wrapped up in a templated handle and handlemanager class. An instance of this is owned by a manager for each type of resource I have, which exposes methods for obtaining a handle for the resource type.class texture_manager{    handle_manager< texture > handles;public:    handle< texture > get_texture( char* szFile )    {   // get texture*, load data   // insert into handlemanager   // return handle    }};;Quote:Oh yes, I know what you mean. Without seeing more of your code, its hard to suggest different ways of doing things. Any chance of posting the headers?Right now I have most of the code IN the header files as a stop-gap measure to avoid template problems. Hopefully this wont be necessary ;-)Quote: What are you using templates to do? I think the layout as suggested could easily be accomplished with standard inheritance?I'm using both templates and inheritance. Templates are used for:1) To generalize `Resource_lookup' to any map key type. Usually a std::string filename would be used, but parameterizing it allows me to use this class when a filename is not enough to distinguish different resources (say, two textures using the same base image, but using different filtering, mipmapping, etc).2) In `create()'. This is a static function in class `Resource_lookup' (two levels of parameterization here, yuk!) that performs the map lookup or new()'ing of a resource. The parameter is required so the right object is new()'d, or the pointer is dynamic_cast() to the correct type.3) In `Handle_base' which provides some virtual functions and operators useful in all handles. Template parameter is needed because this class's constructor calls other parameterized functions. (4 template layers.)Add to this my attempt at rigorous encapsulation which introduces the need for template friends (argh!!). As you can see I've totally over-engineered the problem.Quote:This is an outline of what i have for a resource manager....I avoided the use of templates and went with derived classes instead. Holding pointers to a parrent class and casting down to the other classesI thought about a method like yours, but decided I wanted to totally encapsulate memory management. Your method would certainly remove the need for at least one set of templates.Quote:The common code I have for resources really is just linking handle ids to whatever-the-resource-class-is*. So for me, that part is wrapped up in a templated handle and handlemanager class. An instance of this is owned by a manager for each type of resource I have, which exposes methods for obtaining a handle for the resource type.Ok, so your resource-manager classes don't inherit from some common base class? Perhaps I should do away with the extra layer of generality. I think it's a less elegent solution from an OO design standpoint, but I'd be stretching the definition slightly to call my currently implementation elegent ;-)   ;  I dislike the use of handles for this sort of thing.Personally I do something like this: interpreter    [opt] global instanceVV  ^^base_manager -> base_manager<base_type> -> concrete_manager;^^   logger    base_type-> concrete_typeThe base manager is templated to specify the type returned by base_manager<T>::Load, and what functors the interpreter accepts. [note: boost::shared_ptr's help greatly here. By specifying the destruction method to the ptr, you can Release() textures or otherwise get the ptr to call an unload without requiring that of the programmer]Next comes an abstraction layer to define an abstract base class [image] and perhaps a global instance of the abstract image manager [base_manager<base_image>]. Finally comes the actual implimentation, which defines various loaders for the manager, configures the interpreter to accept them, the concrete type, and usually a few other things specific to the concrete implimentation.That last part would be something like d3d_image, and d3d_image_manager which take a command and return an abstract image. The code is fairly nice and neat. If you want to make everything go through one manager, it would be fairly trivial to impliment a base_manager<base_manager>, though I don't care for that approach.   ;Quote:Right now I have most of the code IN the header files as a stop-gap measure to avoid template problems. Hopefully this wont be necessary ;-)Quote: What are you using templates to do? I think the layout as suggested could easily be accomplished with standard inheritance?I'm using both templates and inheritance. Templates are used for:1) To generalize `Resource_lookup' to any map key type. Usually a std::string filename would be used, but parameterizing it allows me to use this class when a filename is not enough to distinguish different resources (say, two textures using the same base image, but using different filtering, mipmapping, etc).2) In `create()'. This is a static function in class `Resource_lookup' (two levels of parameterization here, yuk!) that performs the map lookup or new()'ing of a resource. The parameter is required so the right object is new()'d, or the pointer is dynamic_cast() to the correct type.3) In `Handle_base' which provides some virtual functions and operators useful in all handles. Template parameter is needed because this class's constructor calls other parameterized functions. (4 template layers.)Add to this my attempt at rigorous encapsulation which introduces the need for template friends (argh!!). As you can see I've totally over-engineered the problem.A problem I found, like you say, with having a custom resource_lookup base is when you have resources specified by things other than just one file path, for example, fonts defined by a face, size and formating flags (bold, italic etc). The way around that I used was to have a very lightweight resource definition object, basically containing the data for loading a resource, and operator==. For example:struct font_def{std::string face;int height;unsigned long flags;bool operator==(font_def& d){return face==d.face && height==d.height&&flags==d.flags;}};};This lets me quickly search for existing instances of a resource, and looks clean in the templated code. It's also nice to hand off to the resource loading method. So my handles are definied by three things really, the type of resource pointer they return, a definition of how/what to load, and a manager type to turn that loading data into that type of pointer.Quote:This is an outline of what i have for a resource manager....I avoided the use of templates and went with derived classes instead. Holding pointers to a parrent class and casting down to the other classesI thought about a method like yours, but decided I wanted to totally encapsulate memory management. Your method would certainly remove the need for at least one set of templates.I'm not sure I follow. You can still easily use custom memory management either way. Mine does by using custom new/delete methods.Quote:Ok, so your resource-manager classes don't inherit from some common base class? Perhaps I should do away with the extra layer of generality. I think it's a less elegent solution from an OO design standpoint, but I'd be stretching the definition slightly to call my currently implementation elegent ;-)The only common class is the handle management stuff, which follow a has-a pattern rather than is-a. I did have a common base at one point, using a reference counting system, but I ultimately decided that handles really made this unnecessary. Because a handle is just a number, an index into a list of resources for all intents and purposes, your resource managers can unload them any time they like as long as they have the necessary data stored to be able to reload them. Given they are in a list, you can just store that list based on how often resources are requested, and unload the bottom most. The code using a handle can just assume the resource is valid and doesn't have to worry about loading or unloading.;Quote:I'm not sure I follow. You can still easily use custom memory management either way. Mine does by using custom new/delete methods.I was actually commenting on KulSeran's code.Quote:The way around that I used was to have a very lightweight resource definition object, basically containing the data for loading a resource, and operator==.This is why I parameterized my Resource_lookup base class, but that is a must nicer method. Thanks!Quote:I dislike the use of handles for this sort of thing.My `handle' is more or a less a shared_ptr. It basically wraps a pointer with a `const operator->' so I can access members of the resource. Unfortunately it's the resource part that doesn't work too well; the handles work nicely.Thanks for all your suggestions. I'll have another go today and see what I come up with.   