[C con Clase] Busco ayuda con manager de recursos

Ferran Ferri ferranferri en gmail.com
Mar Sep 30 01:15:17 CEST 2008


Hola,
dejad que introduzca el problema que pretendo resolver para que quede bien
explicado. Imaginemos que tenemos un programa que carga imagenes y trabaja
con ellas. Las imagenes van a memoria RAM y la carga viene de disco. Nadie
quiere cargar la misma imagen dos veces, asi que tenemos que aplicar logica
extra para evitarlo. Yo uso una clase que gestiona los recursos. En general,
la primera vez que se carga una clase, usando path + nombre (que es unico en
cada maquina), la clase se carga en un vector, y la clase CResourceManager
devuelve un puntero a la clase. Cuando se intenta crear la clase por segunda
vez, CResourceManager, la busca en un mapa, recoge la clave, que es el
indice del vector y devuelve el puntero a la informacion. Os pongo un
ejemplo de como la implemento:

===================================================================================
ResourceManager.h
===================================================================================
#ifndef _CRESOURCEMANAGER_H_
#define _CRESOURCEMANAGER_H_


#include <vector>
#include <map>
#include <iterator>
#include "SampleResource.h"

using std::vector;
using std::string;
using std::map;
using std::iterator;



class CResourceManager
{
    static const unsigned int MAX_ITEMS = 200;
    typedef struct stLoadedResource
    {
        CSampleResource* res;
        unsigned int nInstances;
    };

    map<string,unsigned int>    m_handlesMap;
    vector<stLoadedResource>    m_resourceList;
    vector<unsigned int>        m_avaiableItems;

public:
    CSampleResource* getResource(string path, string name);
    void releaseResource(string path,string name);
    CResourceManager(void);
    ~CResourceManager(void);
};

#endif //_CRESOURCEMANAGER_H_


===================================================================================
ResourceManager.cpp
===================================================================================
#include "ResourceManager.h"

CResourceManager::CResourceManager(void):m_resourceList(MAX_ITEMS)
{
    for (unsigned int i = 0; i < MAX_ITEMS; i++)
    {
        m_avaiableItems.push_back(i);
    }
}

CResourceManager::~CResourceManager(void)
{
}

CSampleResource* CResourceManager::getResource( string path, string name)
{
    string fullPath = path + name;
    unsigned int index;
    // buscar el elemento en el mapa
    map<string,unsigned int>::iterator it = m_handlesMap.find(fullPath);
    // si no hemos cargado previamente este recurso
    if (it == m_handlesMap.end())
    {
        index = m_avaiableItems.back();
        // una vez creado lo metemos en el vector en la primera entrada
libre que tenemos
        m_resourceList[index].nInstances = 0;
        m_resourceList[index].res = new CSampleResource();
        m_resourceList[index].res->load(path,name);

        // y actualizamos el mapa
        m_handlesMap[fullPath] = index;
        // actualizamos los elementos libres descartando el que hemos usado
        m_avaiableItems.pop_back();
    }else
    {
        index = it->second;
    }
    m_resourceList[index].nInstances++;
    // y devolvemos el resultado
    return m_resourceList[index].res;
}

void CResourceManager::releaseResource( string path,string name )
{
    string fullPath = path + name;
    unsigned int index;
    // buscar el elemento en el mapa
    map<string,unsigned int>::iterator it = m_handlesMap.find(fullPath);
    // si hemos cargado previamente este recurso
    if (it != m_handlesMap.end()){
        index = it->second;
        m_resourceList[index].nInstances--;
        // si era la ultima instancia
        if (m_resourceList[index].nInstances == 0)
        {
            delete m_resourceList[index].res;    // llamamos al destructor
de la clase
            m_resourceList[index].res = NULL;    // ponemos un null de
seguridad
            m_avaiableItems.push_back(index);    // actualizar la lista de
indices vacios
            map.erase(it);                        // borrar la entrada del
mapa
        }
    }
    return;

}

===================================================================================
SampleResource.h
===================================================================================
#ifndef _CSAMPLERESOURCE_H_
#define _CSAMPLERESOURCE_H_



#include <string>
#include <fstream>
#include <iostream>
#include <vector>

using std::string;
using std::cout;
using std::fstream;
using std::ifstream;
using std::vector;

class CSampleResource//:public IResource
{
    typedef vector<string> vectorText;
private:
    vectorText m_text;
public:
    /*
    void* loadResource(string path, string name, unsigned int hadle){
        load(path,name);
        return this;
    }
    bool releaseResource(){return true;}
    */
    void render(){
        vector<string>::iterator i = m_text.begin();
        while (i != m_text.end())
        {
            cout << *i++ << std::endl;
        }
    }

    void load(string path, string name){
        string fullName = path + name;
        ifstream myfile(fullName.c_str());
        if (myfile.is_open())
        {
            while (!myfile.eof())
            {
                string s;
                getline(myfile,s);
                m_text.push_back(s);
            }
            myfile.close();
        }
        else cout << "Unable to open file" << std::endl;
    }
    CSampleResource(void){}

    ~CSampleResource(void){    }
};

#endif //_CSAMPLERESOURCE_H_
===================================================================================
Main.cpp
===================================================================================

#include "SampleResource.h"
#include "ResourceManager.h"

int main () {
    CResourceManager resManager = CResourceManager();
    CSampleResource* sr = resManager.getResource("./","log.txt");
    CSampleResource* sr2 = resManager.getResource("./","log.txt");
    CSampleResource* sr3 = resManager.getResource("./","log2.txt");
    sr->render();
    sr2->render();
    sr3->render();

    system("PAUSE");
    return EXIT_SUCCESS;
}
===================================================================================

Como podeis ver el diseño tiene algunos errores pero sirve como ejemplo,
creo. Ahora viene la pregunta. Mi idea es que si se puede hacer con una
clase, por que no hacerlo con varias y gestionar varios tipos de recursos en
una sola clase? Al principio habia pensado en hacer un template, y entonces
tendria tantos managers como tipos de recursos, pero lo que busco es usar
bien el polimorfismo para poder gestionarlas todas en una sola clase. Eso da
una serie de problemas de diseño que no consigo responder. Para empezar, la
funcion load será diferente para cada clase. Ademas, en getResource se el
tipo que tengo que guardar en el vector, pero si tengo varias clases eso ya
no vale.

La primera idea que tengo es substituir la funcion de carga por un puntero a
funcion, pero, donde lo guardo? Por que esta clase guardará varios tipos de
clases, pero de cada clase podra haber varias instancias (una por archivo).

No se.. estoy hecho un lio. Me podeis echar una mano?

Ferran
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20080930/66b6011b/attachment.html>


Más información sobre la lista de distribución Cconclase