1 pièce(s) jointe(s)
[Source][C++]Manageur de ressource generique et intelligent
Bonjours a tous,
Pour ce premier post sur developpez.com, je vous propose une class qui tente de répondre au problématiques suivantes:
- Stocker des objets d'un type définie(template)
- Pouvoir récupérer ces objets a l'aide d'une clé(tableau associatif)
- Détruire les objets qui ne sont plus utilisés ailleurs que dans le conteneur
- Et éventuellement créer l'objet demandé si il n'est pas déjà présent dans le conteneur
Concrètement, il s'agit d'un std::map associant une clé template a un boost::weak_ptr<>, avec une fonction "Factory" que l'on peu lui passer.
Une map de shared_ptr n'aurait pas permit le delete, c'est pourquoi j'utilise les weak_ptr, qui sont transformé en shared_ptr lorsqu'ils sont requis.
Avant tout voici le code:
Code:
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
| #include <boost/weak_ptr.hpp>
#include <boost/function.hpp>
#include <boost/foreach.hpp>
#include <map>
namespace Blas
{
template<class K, class V>
class weak_map
{
typedef std::map<K, boost::weak_ptr<V> > WeakMapType; //Type du conteneur interne
typedef typename WeakMapType::iterator iterator; //Type de l'itérateur
typedef typename WeakMapType::const_iterator const_iterator; //Type de l'itérateur const
typedef boost::function1<boost::shared_ptr<V>, const K&> Factory; //Type de la fonction de la factory
WeakMapType _weakMap; //Conteneur
Factory _factory; //Fonction factory
public:
//Constructeur et définition du pointeur sur la factory
weak_map(Factory f = 0):_factory(f)
{
}
//Fait un ajout dans le tableau associatif
void add(const K &key, const boost::shared_ptr<V> &sptr)
{
std::pair<iterator, bool> res = _weakMap.insert( std::pair<K, boost::weak_ptr<V> >(key, boost::weak_ptr<V>(sptr)));
if(res.second == false)
{
//Si l'élément existe déjà, il n'a pas été modifié.
//Donc il faut le faire, car c'est que le pointeur était NULL
// (Ou alors il se passe une chose très étrange...)
boost::weak_ptr<V> &wptr = res.first->second;
wptr = boost::weak_ptr<V>(sptr);
}
}
//Récupère une ressource. (sinon, ou un shared_ptr NULL)
//(Peut renvoyer les exceptions du _factory)
boost::shared_ptr<V> get(const K &key)
{
iterator iter = _weakMap.find(key);
if(iter != _weakMap.end())
{
//Si on a trouvé l'objet associé à la clé
boost::weak_ptr<V> &wptrPtr = iter->second;
if(wptrPtr.expired() == false) //Et qu'il n'a pas déjà été détruit
return boost::shared_ptr<V>(wptrPtr);
}
//Si on a pas trouvé l'objet...
if(_factory)
{
//...et qu'une fonction factory a été définie, on l'utilise
boost::shared_ptr<V> sptr(_factory(key));
add(key, sptr);
return sptr;
}
//...et que la fonction factory n'est pas définie, on renvoie un shared_ptr NULL
return boost::shared_ptr<V>();
}
//Renvoie le nombre de ressources encore allouées
int getNbUnexpired() const
{
int count = 0;
const_iterator iterEnd = _weakMap.end();
for(const_iterator pairIter = _weakMap.begin();
pairIter != iterEnd;
pairIter++)
{
if(pairIter->second.expired() == false)
count ++;
}
return count;
}
};
} |
Pour l'exemple, supposons que vous ayez une factory qui vous construise un objet MyObject à partir d'un seul paramètre(pour commencer), disons un int.
Maintenant vous voulez être sur qu'on ne crée pas en double un MyObject identique dans vote code. Mais que cette objet partagé soit détruit lorsqu'il n'est plus utilisé:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
//Ma factory
shared_ptr<MyObject> factory(int);
//Mon gestionnaire de ressources
weak_map<int, MyObject> objectMap(factory);
{
//Comme l'objet n'éxiste pas deja, il sera crée
shared_ptr<MyObject> obj1 = objectMap.get(586);
//Comme il existe deja, il sera juste partagé entre deux shared_ptr
shared_ptr<MyObject> obj2 = objectMap.get(586);
}
//En sortant du scope, les shared_ptr seront détruit, et l'objet aussi. |
Il est a notez que la fonction factory peut très bien être membre d'une class, à condition d'utiliser boost::bind.
Au passage, il est tout a fait possible de créer une clef(et donc une factory) avec plusieurs paramètres, en utilisant le boost::tuple. Vous pourrez le voir dans les exemples joints. (Projet code::block/minGW, probablement compilable sur n'importe quel compilo C++ récent, à condition d'inclure boost dans les chemin de recherche des .hpp)
Ceci dit, ma première question est de savoir si vous trouvez une utilité a cette objet. En effet cette objet semble pouvoir résoudre beaucoup de soucie dans mon code, mais à t'il un réel intérêt d'un point de vu général?
Si c'est le cas alors comment pourrait-on l'optimiser?
(oui je sait bien que faire une map de weak_ptr c'est pas optimum^^)
Et aussi auriez vous des suggestion pour élargir ces possibilité?
Enfin, si vous avez des critiques, n'hésitez pas!