Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Classe template Singleton

6 réponses
Avatar
Michael
Bonsoir à tous,

tout d'abord bonne année et bonne santé à vous tous!

Vient ensuite quelques questions sur une classe singleton que j'ai créé:

template <class T>
class Singleton
{
public :

static T* getInstance()
{
if (!instance) instance = new T;
return instance;
}

static void Release()
{
if (instance) delete instance;
instance = NULL;
}

protected :
Singleton() {}
~Singleton() {}

private :
static T* instance;
Singleton(Singleton&);
void operator =(Singleton&);
};

template <class T> T* Singleton<T>::instance = NULL;

Là comme ça elle marche très bien:

class Configuration : Singleton<Configuration>
{
private:
friend Singleton<Configuration>;
};

Et je l'instancie comme ça:

Configuration *Options = Configuration::getInstance();

Seulement comment puis-je la modifier si je veux passer un paramètre lors
de la création?

Ex: Configuration *Options = Configuration::getInstance(8);

Faut-il que je passe par des spécialisations templates? Si oui comment je
peux faire ça?

Deuxième question: est-il possible de rendre cette classe Singleton auto-
destructible quand aucun pointeur ne pointe dessus?

Merci d'avance

@ Bientôt

Mike

6 réponses

Avatar
Pierre Lairez
Salut,


Seulement comment puis-je la modifier si je veux passer un paramètre lors
de la création?

Ex: Configuration *Options = Configuration::getInstance(8);



Oui, il suffit de définir "static T* getInstance(int)". Mais c'est pas
bien.
Parce que par définition du Singleton, il n'y a pas de création. On accède
juste à un objet déjà créé. Pour ma part, je pense qu'une sémantique comme
suit serait plus adaptée:

Configuration *Options = Configuration::getInstance();
Options->SetValue(8);



Deuxième question: est-il possible de rendre cette classe Singleton auto-
destructible quand aucun pointeur ne pointe dessus?


Non, là aussi par définition du Singleton. Un Singleton _est_ est
_restera_. Quelle sens aurait un Singleton si il était détruit quand rien
ne pointe dessus ?



La question qui se pose est: le modèle Singleton est-il une solution
judicieuse à ton problème ?




Le 03 Jan 2005 23:56:56 GMT, Michael a écrit:

Bonsoir à tous,

tout d'abord bonne année et bonne santé à vous tous!

Vient ensuite quelques questions sur une classe singleton que j'ai créé:

template <class T>
class Singleton
{
public :

static T* getInstance()
{
if (!instance) instance = new T;
return instance;
}

static void Release()
{
if (instance) delete instance;
instance = NULL;
}

protected :
Singleton() {}
~Singleton() {}

private :
static T* instance;
Singleton(Singleton&);
void operator =(Singleton&);
};

template <class T> T* Singleton<T>::instance = NULL;

Là comme ça elle marche très bien:

class Configuration : Singleton<Configuration>
{
private:
friend Singleton<Configuration>;
};

Et je l'instancie comme ça:

Configuration *Options = Configuration::getInstance();

Seulement comment puis-je la modifier si je veux passer un paramètre lors
de la création?

Ex: Configuration *Options = Configuration::getInstance(8);

Faut-il que je passe par des spécialisations templates? Si oui comment je
peux faire ça?

Deuxième question: est-il possible de rendre cette classe Singleton auto-
destructible quand aucun pointeur ne pointe dessus?

Merci d'avance

@ Bientôt

Mike


Avatar
drkm
"Pierre Lairez" writes:

Seulement comment puis-je la modifier si je veux passer un paramètre lors
de la création?

Ex: Configuration *Options = Configuration::getInstance(8);


Oui, il suffit de définir "static T* getInstance(int)". Mais c'est pas
bien.
Parce que par définition du Singleton, il n'y a pas de création. On accède
juste à un objet déjà créé. Pour ma part, je pense qu'une sémantique comme
suit serait plus adaptée:

Configuration *Options = Configuration::getInstance();
Options->SetValue(8);


Pour ça, il faudrait en savoir plus. Un modèle de conception n'est
pas une recette figée. Peut-être qu'une adaptation gérant quelques
instances au lieu d'une seule serait utile dans le cadre du PO.

--drkm


Avatar
kanze
Michael wrote:

Vient ensuite quelques questions sur une classe singleton que
j'ai créé:

template <class T>
class Singleton
{
public :

static T* getInstance()
{
if (!instance) instance = new T;
return instance;
}

static void Release()
{
if (instance) delete instance;
instance = NULL;
}

protected :
Singleton() {}
~Singleton() {}

private :
static T* instance;
Singleton(Singleton&);
void operator =(Singleton&);
};

template <class T> T* Singleton<T>::instance = NULL;

Là comme ça elle marche très bien:

class Configuration : Singleton<Configuration>


class Configuration : public Singleton< Configuration >

en fait, j'imagine.

{
private:
friend Singleton<Configuration>;
};

Et je l'instancie comme ça:

Configuration *Options = Configuration::getInstance();

Seulement comment puis-je la modifier si je veux passer un
paramètre lors de la création?


Laisse tomber le template, et séparer la création et l'accès à
l'instance :

class Configuration
{
public:
static Configuration& instance() ;
static void initialize(
std::string const& configFilename )
;
// ...

private:
// ...
static Configuration* ourInstance ;
} ;

Configuration&
Configuration::getInstance()
{
assert( ourInstance != NULL ) ;
return *ourInstance ;
}

void
Configuration::initialize(
std::string const& configFilename )
{
assert( ourInstance == NULL ) ;
ourInstance = new Configuration( configFilename ) ;
}

Ex: Configuration *Options = Configuration::getInstance(8);

Faut-il que je passe par des spécialisations templates? Si oui
comment je peux faire ça?


Même pas une spécialisation. Pas de template du tout.

Deuxième question: est-il possible de rendre cette classe
Singleton auto- destructible quand aucun pointeur ne pointe
dessus?


Évidemment (mais ce ne serait plus ce que j'entends par
Singleton:-)). À la place d'une référence (ou un pointeur
brut), instance renvoie un pointeur intelligent qui gère un
compteur.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
kanze
drkm wrote:
"Pierre Lairez" writes:

Seulement comment puis-je la modifier si je veux passer un
paramètre lors de la création?

Ex: Configuration *Options = Configuration::getInstance(8);


Oui, il suffit de définir "static T* getInstance(int)". Mais
c'est pas bien. Parce que par définition du Singleton, il
n'y a pas de création. On accède juste à un objet déjà cré é.
Pour ma part, je pense qu'une sémantique comme suit serait
plus adaptée:

Configuration *Options = Configuration::getInstance();
Options->SetValue(8);


Pour ça, il faudrait en savoir plus. Un modèle de conception
n'est pas une recette figée. Peut-être qu'une adaptation
gérant quelques instances au lieu d'une seule serait utile
dans le cadre du PO.


Tout à fait. J'ai un cas où le singleton est caractèrisé par un
paramètre, et ce qu'il faut, c'est une instance unique pour un
paramètre donné. Ça marche exactement comme un singleton
classique, sauf que la fonction instance prend le paramètre, et
j'ai un std::map< ParamType, Singleton* > à la place d'un simple
pointeur.

Dans mon cas, ça sert à gérer des « bases de données », mais je
le verais aussi pour la gestion des imprimantes, par exemple
(une instance de Printer par imprimante), des écrans d'un
terminal, des terminaux attachés à une application...

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
Michael
class Configuration : public Singleton< Configuration >

en fait, j'imagine.


Oui, oubli de ma part...

Deuxième question: est-il possible de rendre cette classe
Singleton auto- destructible quand aucun pointeur ne pointe
dessus?


Évidemment (mais ce ne serait plus ce que j'entends par
Singleton:-)). À la place d'une référence (ou un pointeur
brut), instance renvoie un pointeur intelligent qui gère un
compteur.


Ce que je voudrais faire avec ça, c'est par exemple dans le cas de la
connexion à une BDD, supprimer l'instance quand il n'y a plus de
connexion...


Avatar
kanze
Michael wrote:
class Configuration : public Singleton< Configuration >

en fait, j'imagine.


Oui, oubli de ma part...

Deuxième question: est-il possible de rendre cette classe
Singleton auto- destructible quand aucun pointeur ne pointe
dessus?


Évidemment (mais ce ne serait plus ce que j'entends par
Singleton:-)). À la place d'une référence (ou un pointeur
brut), instance renvoie un pointeur intelligent qui gère un
compteur.


Ce que je voudrais faire avec ça, c'est par exemple dans le
cas de la connexion à une BDD, supprimer l'instance quand il
n'y a plus de connexion...


Et il peut y avoir plusieurs connections ? Ce n'est vraiment pas
ce qu'on appelle d'habitude un singleton:-).

Supprimer l'instance quand il n'y a plus de connection est
trivial. C'est la classe de connection qui reconnaît que la
connection est tombée, n'est-ce pas ? Alors, elle n'a qu'à faire
« delete this ». Évidemment, c'est là que le bat blesse, parce
qu'il faut aussi trouver tous les pointeurs, et les mettre à
zéro. À ma site, il y a un pointeur intelligent qui s'occupe de
ce genre de chose (GB_ManagedPtr), mais il faut bien d'abord
définir ce que tu veux exactement. (Par exemple, est-ce qu'on
laisse tomber la connection exprès quand personne n'en detient
un pointeur vers l'instance.)

Enfin, je verrais bien un espèce de ConnectionManager, qui lui
serait un singleton (dans le sens classique). Quand un client
veut utliser une connection, il s'adresse au CollectionManager
en lui donnant l'identificateur voulu ; il reçoit en retour un
espèce de shared pointer. Si la connection n'existe pas encore,
la CollectionManager se charge de la créer et de le mettre dans
un map. Et à l'arrivée à zéro du compteur d'utilisation, le
shared pointer s'occupe non seulement de deleter la connection,
mais de l'enveler du map.

Je crois que le tout est faisable avec boost::shared_ptr, avec
un boost::weak_ptr dans le map, mais je ne connais pas Boost
assez bien pour en être sûr. (Boost ne marche pas avec un des
compilateurs que je suis obligé à supporter.) Si j'ai bien
compris la doc, tu peux créer une classe « Deleter » pour ton
objet de connection, et alors, dans la fonction getConnection de
ConnectionManager, tu ferais quelque chose comme :

boost::shared_ptr< Connection >
ConnectionManager::getConnection(
ConnectionId const& id )
{
Map::iterator cx = myMap.find( id ) ;
boost::shared_ptr< Connection >
result ;
if ( result != myMap.end() ) {
result = cx->second.lock() ;
} else {
result = boost::shared_ptr< Connection >(
new Connection( id ),
Deleter( this ) ) ;
myMap.insert(
Map::value_type(
id,
boost::weak_ptr< Connection >( result ) ) );
}
return result ;
}

Deleter, évidemment, est une classe membre de ConnectionManager
qui enlève l'entrée dans le map avant d'effacer l'objet.

(Sans garantie. Comme j'ai dit, je ne peux malheureusement pas
utiliser Boost pour l'instant.)

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34