IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Gestionnaire de mémoire


Sujet :

C++

  1. #1
    Membre éclairé Avatar de seeme
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    430
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 430
    Points : 791
    Points
    791
    Par défaut Gestionnaire de mémoire
    Bonsoir à tous.

    J'ai une question qui va sans doute vous sembler très stupide, mais j'avoue que là je bloque..

    J'ai un gestionnaire de mémoire qui s'occupe de charger des ressources. Pour ce faire, les ressources sont uniquement construites avec le nom (un id unique), et le chemin vers la ressource sur le disque.

    Pour ce faire, j'ai un type abstrait Resource qui a pour membre deux std::string (name et filePath).

    Une fois la ressource "préchargée", si un utilisateur demande au manager de ressource l'accès à une d'elle, le manager va regarder si la ressource est complètement chargée ou seulement préchargée.

    S'il faut charger réellement la ressource, le manager va appeler une ResourceFactory qui va construire le bon objet et renvoyer un Resource* donc.

    Jusque là, ça va..

    Maintenant, comment représenter les données (son, image...) dans la classe abstraite Resource?

    J'ai tenté avec un void*, mais ça devient assez bizarre à gérer.. J'ai pensé au template, mais je ne pense pas que ça se fera plus simplement (même au contraire...)

    Autre question, je voudrais que le manager n'expose pas les ressources. Seulement pour le moment, à part renvoyer un Resource*, je ne vois pas comment faire.. Des idées?

    Il me semble que faire ensemble qu'une seule entité ai la responsabilité d'une ressource porte un nom, si jamais vous pouviez me le rappeler...


    Voilà le gestionnaire de mémoire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    /*
     * ResManager.cpp
     *
     *  Created on: 24 oct. 2010
     *      Author: seeme
     */
     
     
    #include "ResManager.h"
    #include "Resources/ResourceFactory.h"
    #include <queue>
    #include <string>
    #include <fstream>
    #include <boost/algorithm/string.hpp>
    #include "../LogManager/Log.h"
     
     
    using namespace std;
     
    void ResManager::clear(){
    	m_resourceMap.clear();
    	m_nextResourceHandle = "";
    	m_currentUsedMemory = 0;
    	m_maximumMemory = 0;
    }
     
    ResManager::ResManager(){
    	rf = new ResourceFactory();
    	clear();
    }
     
    bool ResManager::create(unsigned int nMaxSize){
    	clear();
    	setMaximumMemory(nMaxSize);
    	return true;
    }
     
     
    void ResManager::destroy(){
    	for(ResMapItor itor = m_resourceMap.begin(); itor != m_resourceMap.end(); ++itor)
    	{
    			delete ((*itor).second);
    	}
    	m_resourceMap.clear();
    	clear();
    }
     
     
    bool ResManager::setMaximumMemory(size_t nMem){
    	m_maximumMemory = nMem;
    	return checkForOverallocation();
    }
     
     
    bool ResManager::reserveMemory(size_t nMem){
    	addMemory(nMem);
    	if(!checkForOverallocation())
    		return false;
    	return true;
    }
     
     
    bool ResManager::destroyResource(HANDLE rhUniqueID){
    	ResMapItor itor = m_resourceMap.find(rhUniqueID);
    	if(itor == m_resourceMap.end()){
    		//Error, not found
    		return false;
    	}
     
    	if(itor->second->getReferenceCount() > 0){
    		return false;
    	}
     
    	if(itor->second->getSize() > 0){
    		itor->second->destroy();
    	}
     
    	return true;
    }
     
     
     
    Resource* ResManager::getResource(HANDLE rhUniqueID){
    	//If it's alread loaded, return it
    	ResMapItor itor = m_resourceMap.find(rhUniqueID);
    	if(itor == m_resourceMap.end()){
    		//Error, not found
    		return NULL;
    	}
     
    	//Is it loaded?
    	if((*itor).second->getSize() == 0){
    		//Not loaded yet, load it
    		(*itor).second->create();
    		m_currentUsedMemory += (*itor).second->getSize();
    	}
     
    	//1up on the ref count
    	//(*itor).second
     
    	//Check memory state
    	checkForOverallocation();
     
    	(*itor).second->upRefCount();
     
    	return (*itor).second;
    }
     
    void ResManager::releaseResource(HANDLE uniqHandle){
    	//Desincrement the ref counter
    	m_resourceMap.find(uniqHandle)->second->downRefCount();
    }
     
    bool ResManager::checkForOverallocation(){
    	if(m_currentUsedMemory > m_maximumMemory){
    		//Over memory, need to free a bit;
     
    		//Remove the resources that are currently not used (refcount = 0)
     
    		priority_queue<Resource*, vector<Resource*>, ptr_greater<Resource*> > PriQueue;
     
    		//Look for the most suitable resource.
    		for(ResMapItor itor = m_resourceMap.begin(); itor != m_resourceMap.end(); ++itor){
    			if(!itor->second->getSize() == 0 && itor->second->getReferenceCount() == 0)
    				PriQueue.push(itor->second);
    		}
     
    		while((!PriQueue.empty()) && (m_currentUsedMemory > m_maximumMemory)){
    			unsigned int nDisposalSize = PriQueue.top()->getSize();
    			PriQueue.top()->destroy();
    			if(PriQueue.top()->getSize() == 0)
    				m_currentUsedMemory -= nDisposalSize;
    			PriQueue.pop();
    		}
     
    	}
    	return true;
    }
     
    void ResManager::setPackageDir(const char* dir){
    	m_packageDir = dir;
    }
     
     
    void ResManager::loadPackage(const char* dir){
    	ifstream file(dir);
    	vector<string> vect;
     
    	ResourceFactory* rf = Singleton<ResourceFactory>::get();
     
    	if (file){
    		string line;
     
    		while(getline(file, line)){
    			if(line.substr(0, 1) != "#"){
    				boost::split(vect, line, boost::is_any_of("|"));
     
    				//vect now contains the data needed for the ressource creation.
    				//Here, the factory comes handy..
    				m_resourceMap.insert(ResMapPair(vect[0], rf->buildResource(vect[0], vect[1], vect[2])));
    			}
    		}
    	}else{
    		Log::e("MemoryManager", "Error Loading Package");
    	}
    }
    La ressource abstraite

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    /*
     * Ressource.h
     *
     *  Created on: 15 oct. 2010
     *      Author: seeme
     *
     *      Based on the article in GamePrograming Gem 3..
     */
     
    #ifndef RESSOURCE_H_
    #define RESSOURCE_H_
    #include <cstddef>
    #include <ctime>
    #include <iostream>
     
    class Resource {
     
    public:
    	enum PriorityType{
    		RES_LOW_PRIORITY = 0,
    		RES_MED_PRIORITY,
    		RES_HIGH_PRIORITY
    	};
     
    	Resource(std::string name, std::string path):m_name(name), m_filePath(path){ clear(); }
    	virtual ~Resource(){ destroy(); }
     
    	virtual void clear();
     
    	//Erase all data
    	virtual bool create(){ return false; }
    	virtual void destroy(){};
     
    	virtual size_t getSize() = 0;
     
    	inline void setPriority(PriorityType priority){ m_priority = priority; }
    	inline PriorityType getPriority(){ return m_priority; }
     
    	inline void upRefCount(){m_refCount += 1;}
    	inline void downRefCount(){
    		if(m_refCount > 0){
    			m_refCount --;
    		}else{
    			//ERROR
    		}
    	}
     
    	inline void setReferenceCount(unsigned int count){ m_refCount = count; }
    	inline unsigned int getReferenceCount(){ return m_refCount; }
     
    	virtual bool operator < (Resource& container);
     
    private:
    	PriorityType m_priority;
    	unsigned int m_refCount;
    	time_t m_lastAccess;
     
    protected:
    	std::string m_filePath;
    	std::string m_name;
    	void*  m_data;
    };
     
    // This class allows an STL object to compare the objects instead of
    // comparing the value of the objects' pointers.
    template <class T>
    class ptr_less
    {
    public:
    	inline bool operator ()(T left, T right)
    	{  return ((*left) < (*right));  }
    };
     
    // This class allows an STL object to compare the objects instead of
    // comparing the value of the objects' pointers.
    template <class T>
    class ptr_greater
    {
    public:
    	inline bool operator ()(T left, T right)
    	{  return !((*left) < (*right));  }
    };
     
    #endif /* RESSOURCE_H_ */
    La Factory (juste là pour que ça marche pour le moment):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    /*
     * ResourceFactory.cpp
     *
     *  Created on: 16 nov. 2010
     *      Author: seeme
     */
     
    #include "ResourceFactory.h"
    #include "TextFile.h"
    #include "Asset.h"
    #include "../../LogManager/Log.h"
     
    Resource* ResourceFactory::buildResource(std::string name, std::string id, std::string realPath){
    	Resource* r;
    	if(id == "txt"){
    		r = new TextFile(name, realPath);
    		return r;
    	}
     
    	if(id == "asset"){
    		r = new Asset(name, realPath);
    		return r;
    	}
     
    	Log::e("RessourceFactory", "Error unknown build parameter");
    	return NULL;
    }
     
    ResourceFactory::ResourceFactory(){
    }
     
    ResourceFactory::~ResourceFactory(){
    }
    Et un exemple de Ressource:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    /*
     * TextFile.cpp
     *
     *  Created on: 16 nov. 2010
     *      Author: seeme
     */
     
    #include "TextFile.h"
    #include <fstream>
     
     
    TextFile::TextFile(std::string fileName, std::string realPath):Resource(fileName, realPath) {
    	std::cout << "New Text File "<< fileName << std::endl;
    }
     
    void TextFile::display(std::string a, std::string b, std::string c){
    	std::cout << a << std::endl;
    	std::cout << b << std::endl;
    	std::cout << c << std::endl;
    }
     
    TextFile::~TextFile() {
    	// TODO Auto-generated destructor stub
    }
     
    bool TextFile::create(){
    	std::cout<<"Create a textfile: " << m_filePath << std::endl;
     
    	std::ifstream file(m_filePath.c_str());
     
    	if (file){
                    //Evidement ça marche pas...
    		m_data = static_cast<filebuf*>(file.rdbuf());
    		file.close();
    		return true;
    	}
     
    	std::cout << "ERROR" << std::endl;
    	return false;
    }
     
    size_t TextFile::getSize(){
            //Evidement ça marche pas...
    	return m_data->str().size();
    }
     
    void TextFile::destroy(){
    	std::cout<<"Destroy a textfile" << std::endl;
     
            //Evidement ça marche pas...
    	delete (filebuf*)m_data;
    }
    Merci d'avance pour tous les conseils que vous pourrez me donner.. Ca fait pas mal de temps que j'avance pas...

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 579
    Points
    218 579
    Billets dans le blog
    120
    Par défaut
    Citation Envoyé par seeme Voir le message
    Une fois la ressource "préchargée", si un utilisateur demande au manager de ressource l'accès à une d'elle, le manager va regarder si la ressource est complètement chargée ou seulement préchargée.
    Je ne sais pas si cette histoire de préchargement / chargement et bien utile. Mais cela dépend de l'objectif que vous avez (personnellement, je charge une bonne fois pour toute et puis je m'en occupe plus (du chargement)).

    Citation Envoyé par seeme Voir le message
    S'il faut charger réellement la ressource, le manager va appeler une ResourceFactory qui va construire le bon objet et renvoyer un Resource* donc.
    Vous avez la réponse à votre question ici :p

    Citation Envoyé par seeme Voir le message
    Maintenant, comment représenter les données (son, image...) dans la classe abstraite Resource?

    J'ai tenté avec un void*, mais ça devient assez bizarre à gérer.. J'ai pensé au template, mais je ne pense pas que ça se fera plus simplement (même au contraire...)

    Autre question, je voudrais que le manager n'expose pas les ressources. Seulement pour le moment, à part renvoyer un Resource*, je ne vois pas comment faire.. Des idées?
    Simplement, que si vous regardez le design pattern de la frabrique (factory), vous savez comment cela doit être structuré.
    Effectivement, dans votre cas, cela retourne une Resource* . Ce qui veut dire, que si vous construisez un son, avec cette fabrique, le Son doit hérité de Resource. Il en est de même pour tout ce qui sort de la fabrique, cela doit hérité de Resource. Donc ce n'est ni un void* ; ni un template. C'est juste du polymorphisme (je crois que c'est le bon nom pour cela). Toute vos ressource (que ce soit des SPrite , des Son, des Billes ou je ne sais quoi, sont des Resource)
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Lorsque tu conçoit un système, il faut non seulement savoir ce que tu veux, mais il faut aussi que la chose ait une certaine logique : tu ne peux pas vouloir considérer que toutes les resources sont essentiellement la même chose tout en souhaitant pouvoir stocker des choses très différentes

    Du coup, et puisque ce que tu fait est essentiellement un cache de ressource (et d'ailleurs, plutôt que resource_manager, ça ne te plairait pas comme nom, resource_cache ?), peut-être que tu n'y stocke pas une ressource complètement créée, mais les outils pour la créer - et le plus petit dénominateur commun de tous tes fichiers, c'est que ce sont des fichiers.

    Du coup, personnellement, je ferais plutôt une classe file_cache, qui stocke le contenu des fichiers lus sous la forme d'un buffer (ou sous une forme plus évoluée, notamment si tu souhaite un jour gérer le chargement asynchrone de données).

    Si besoin, tu peux alors faire un resource_cache qui va construire les ressources proprement dites pour éviter de devoir les reconstruire à chaque fois que tu en a besoins à partir des données du file_cache - mais le resource_cache contient uniquement des ressources du même type (au sens large ; j'entends par là des ressources au comportement similaire, et pas un mélange étrange de ressources graphiques et de ressources sonores, qui n'ont strictement aucune raison d'être mêlées).
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  4. #4
    Membre éclairé Avatar de seeme
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    430
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 430
    Points : 791
    Points
    791
    Par défaut
    Bonjour, et merci pour la réponse

    J'ai pas du m'exprimer clairement en fait

    J'ai 2 problématiques principales.

    Le type ressource contient 2 types de données:
    - Les données minimales (nom, chemin)
    - Les données brutes (pointeur m_data)

    L'idée c'est qu'au lancement de l'application, lesgestionnaire de mémoire lit un package qui contient un fichier d'index et va créer un tableau de Resource* qui contiennent les données minimales.

    Si quelque part dans le programme, quelqu'un demande l'utilisation d'une ressource, le compteur de références de la ressource va s'incrémenter, et si la ressource n'est pas complètement chargée (m_data = NULL), le gestionnaire va appeller la méthode create() qui va initialiser m_data (qui contiendra alors des données de son/image/3D....

    Par exemple, si dans mon package j'ai un asset 3D, au lancement de l'application, le gestionnaire va avoir dans son vecteur de Resource* un pointeur vers un Asset: public Resource qui n'a qu'un nom et un path. Si on demande à utiliser la ressource, elle sera alors effectivement chargée et m_data pointera vers une structure scene d'assimp par exemple.

    Le but c'est de pouvoir charger/décharger des données lourdes (compteur de ref à zero et plus de mémoire par rapport à ce que j'autorise dans le gestionnaire de mémoire) à la volée. Comme tu peux le voir, les ressources ont aussi des priorités, ce qui me permet de faire le ménage et ainsi d'utiliser un espace raisonable de mémoire. Par exemple, dans un jeu, le model du personnage aura une priorité très haute, voir sera locked (pas encore implémenté), ce qui empêchera le gestionnaire de l'effacer s'il manque de place. Par contre, le modèle d'une plante qui aura une priorité plus basse, dont le compteur de ref est à zero (personne ne l'utilise) et qui n'a pas été demandée depuis longtemps pourra être supprimée pour faire de la place.

    L'idée à terme est d'ajouter un traitement statistique pour ajuster les priorités à la volée.

    Donc mon problème est le suivant: dois-je représenter ces données brutes (qui seront finalement un stream pour les fichiers texte, un graphscene pour les assets ou encore une image pour les textures) dans la classe abstraite Resource, et si oui, de quel type le pointeur doit être? (on m'a parlé de boost::any)

    Ma deuxième problèmatique concerne le manager. Le but, c'est que seul le manager ai la responsabilité de réserver ou de libérer de la mémoire. Il utilise l'interface Resource pour pouvoir gérer celà.

    Le problème, c'est que tel quel, j'expose un Resource*, ce qui fait que si quelqu'un fait un delete dessus, je vais finir par avoir un null pointer.

    Il est possible d'utiliser des handle afin de cacher le pointeur, mais je ne vois pas comment faire.

    Une autre idée serait de mettre un constructeur privé pour les Resource, mais friend avec le ResourceManager. Du coup, personne ne pourra les delete sauf le gestionnaire.. Cette idée est-elle valable?

    La technique correspondant consiste à avoir un scope très stricte pour la création et la destruction d'objets. Je me souvient que c'est un acronyme, c'est tout..


    Merci

  5. #5
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par seeme Voir le message
    Ma deuxième problèmatique concerne le manager. Le but, c'est que seul le manager ai la responsabilité de réserver ou de libérer de la mémoire. Il utilise l'interface Resource pour pouvoir gérer celà.

    Le problème, c'est que tel quel, j'expose un Resource*, ce qui fait que si quelqu'un fait un delete dessus, je vais finir par avoir un null pointer.

    Il est possible d'utiliser des handle afin de cacher le pointeur, mais je ne vois pas comment faire.

    Une autre idée serait de mettre un constructeur privé pour les Resource, mais friend avec le ResourceManager. Du coup, personne ne pourra les delete sauf le gestionnaire.. Cette idée est-elle valable?

    La technique correspondant consiste à avoir un scope très stricte pour la création et la destruction d'objets. Je me souvient que c'est un acronyme, c'est tout..


    Merci
    Le problème de la suppression de ressources par l'utilisateur est géré très simplement : le destructeur est privé, et la classe de gestion des ressources est déclarée comme étant une classe amie. Du coup, elle seule peut faire la destruction d'une ressource (même en dérivant la classe, tu n'accèderas pas au destructeur privé).

    Idem pour le constructeur.

    Le mot-clef friend est prévu pour ces cas là, il ne faut donc pas hésiter à s'en servir.

    Quand à la définition du scope d'existence de la variable, elle est effectivement celle du manager (mes dents me font mal lorsque j'écris ce terme). Je supposes que tu voulais parler de RAII - resource acquisision is initialisation. Ce n'est pas nécessairement adapté à ton cas précis, puisque à terme tu veut avoir un contrôle plus fin de la durée de vie de test objets.

    Citation Envoyé par seeme Voir le message
    Donc mon problème est le suivant: dois-je représenter ces données brutes (qui seront finalement un stream pour les fichiers texte, un graphscene pour les assets ou encore une image pour les textures) dans la classe abstraite Resource, et si oui, de quel type le pointeur doit être? (on m'a parlé de boost::any)
    Comme je l'ai dit : ce sont des choses différentes, ayant un comportement différent. Tu ne peux pas, conceptuellement, les représenter via une interface unique, à moins de restreindre cette interface au strict minimum, c'est à dire à stocker le nom, le nom du fichier et le contenu du fichier - charge à celui qui va interpréter les données de le faire correctement.

    Si tu souhaites quand même le faire, il y a une astuce : l'utilisation de visiteurs, qui te permet de récupérer une interface autre que l'interface originelle de la classe.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
     
    // forward declarations
    class my_resource;
    class m_other_resource;
     
    // la classe de base du visiteur : il suffit d'hériter de cette interface
    // pour faire ce qu'on veux (généralement avec une seule des classes
    // de la liste des classes connues). 
    class rsc_visitor
    {
    public:
      virtual void accept(my_resource& r) = 0;
      virtual void accept(my_other_resource& r) = 0;
    };
     
    // la classe de base de ressources
    class resource
    {
    public:
      virtual void visit(rsc_visitor& v) = 0;
    };
     
    class my_resource
    {
    public:
      // le type de l'objet passé en paramètre est my_resource&
      virtual void visit(rsc_visitor& v) { v.accept(*this); }
     
      void do_thing();
    };
     
    class my_other_resource
    {
    public:
      // le type de l'objet passé en paramètre est my_other_resource&
      virtual void visit(rsc_visitor& v) { v.accept(*this); }
     
      void do_other_thing();
    };
     
    class do_thing_visitor : public rsc_visitor
    {
    public:
      virtual void accept(my_resource& r)
      { r.do_thing(); }
      virtual void accept(my_other_resource& r)
      { r.do_other_thing(); }
    };
     
    // on peut créer autant de visiteur qu'on le souhaite pour faire 
    // ce qu'on veut. Par exemple, un visiteur spécialisé dans les textures 
    // va récupérer la texture, tandis qu'un visiteur spécialisés dans les 
    // graphscene va récupérer un graphscene.
    A noter qu'il est courant d'implémenter le visiteur sous sa forme dite acyclique.

    boost.any n'est l'ami de personne, sauf peut-être des personnes qui veulent s'essayer à la méta-programmation, et encore. Any résous un problème qui ne devrait pas exister à la base. Son utilisation doit être pensée et repensée (à l'heure actuelle, je n'en voit aucune de valide).
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  6. #6
    Membre éclairé Avatar de seeme
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    430
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 430
    Points : 791
    Points
    791
    Par défaut
    Merci beaucoup! J'avoue que je n'avais pas vu ta première réponse.

    Au final ça rejoins ce que j'avais fait à la révision précédente.. Les ressources ont seulement l'id de la ressource et le path vers le fichier. Les données brut sont dans les classes qui héritent de cette interface.

    C'était bien RAII que je cherchait, merci beaucoup

    Je vois bien la différence entre la notion de manager et de cache et effectivement, ça tend plus vers le cache de fichier.

    Par contre, dans ma tête, un cache sous entendait qu'on prémachait le chargement, c'est à dire qu'on charge les données brutes, et qu'on les sauve sous une forme plus "primitive", plus proche de la machine, pour pouvoir les recharger plus rapidement (c'est ce que j'ai compris de ton explication avec le buffer).

    Enfin, je vais regarder le pattern visitor, je me suis pas tellement penché dessus pour le moment et je ne veut pas cacher des faiblesses de conceptions derrière des patterns que je ne maitris epas (encore).

    Je vais donc mettre en application le constructeur+destructeur privés et friend avec le cache et essayer de voir comment gérer ce buffer de données brutes.

    Par contre, pour l'exemple, je vais utiliser assimp qui me renvoie une structure assez balaise de données pour le chargement de modèles 3D. J'avoue que je ne vois pas comment cacher ce genre de données, sans perdre les relations entre les informations, ni mettre plus de temps à faire ça plutôt qu'un chargement classique.

    En fait.. En relisant mon post, je me rend compte que pour moi, la notion de cache est assez floue, et consiste à se rapprocher de données raw, mais j'ai de sérieux doutes...

Discussions similaires

  1. Conflit entre mon gestionnaire de mémoire et afxmem
    Par mister3957 dans le forum C++
    Réponses: 9
    Dernier message: 30/06/2008, 12h52
  2. Réponses: 4
    Dernier message: 02/06/2008, 20h12
  3. Réponses: 10
    Dernier message: 20/08/2007, 10h47
  4. gestionnaire de mémoire en c
    Par kagemusha dans le forum C
    Réponses: 13
    Dernier message: 14/10/2006, 11h06
  5. Réponses: 1
    Dernier message: 27/06/2006, 20h28

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo