Considérons la structure de classe suivante:Comment gérer différentes stratégies de propriété pour un membre de pointeur?
class Filter
{
virtual void filter() = 0;
virtual ~Filter() { }
};
class FilterChain : public Filter
{
FilterChain(collection<Filter*> filters)
{
// copies "filters" to some internal list
// (the pointers are copied, not the filters themselves)
}
~FilterChain()
{
// What do I do here?
}
void filter()
{
// execute filters in sequence
}
};
J'expose la classe dans une bibliothèque, donc je n'ai pas le contrôle sur la façon dont il sera utilisé. Je rencontre actuellement quelques problèmes de conception concernant la propriété des objets Filter
FilterChain
tient les pointeurs à. Plus précisément, voici deux scénarios d'utilisation possibles pour FilterChain
:
- Scénario A: quelques-unes des fonctions dans ma bibliothèque sont la construction d'une (éventuellement complexe) chaîne de filtrage, l'allocation de mémoire si nécessaire, et le retour d'un nouveau alloué
FilterChain
objet. Par exemple, une de ces fonctions construit une chaîne de filtres à partir d'un fichier, qui peut décrire des filtres arbitrairement complexes (y compris des chaînes de filtres de chaînes de filtres, etc.). L'utilisateur de la fonction est responsable de la destruction de l'objet une fois le travail terminé. - Scénario B: l'utilisateur a accès à un groupe d'objets
Filter
et souhaite les combiner dans des chaînes de filtres d'une manière spécifique. L'utilisateur construitFilterChain
objets pour son propre usage, puis les détruit lorsqu'il en a fini avec lui. Les objetsFilter
ne doivent pas être être détruits lorsqu'unFilterChain
les référençant est détruit.
Maintenant, les deux moyens les plus simples pour gérer la propriété dans l'objet FilterChain
sont:
FilterChain
possèdent lesFilter
objets. Cela signifie que les objets référencés parFilterChain
sont détruits dans le destructeurFilterChain
. Ce qui est incompatible avec le scénario B.FilterChain
ne pas posséder les objetsFilter
. Cela signifie que le destructeur deFilterChain
ne fait rien. Maintenant, il y a un problème avec le scénario A, car l'utilisateur devrait connaître la structure interne de tous les objets impliqués afin de les détruire sans en manquer un, car le parentFilterChain
ne le fait pas lui-même. C'est juste une mauvaise conception, et demander des fuites de mémoire.
Par conséquent, j'ai besoin de quelque chose de plus compliqué. Ma première supposition est de concevoir un pointeur intelligent avec un indicateur booléen réglable indiquant si oui ou non le pointeur intelligent possède l'objet. Puis, au lieu de prendre une collection de pointeurs vers Filter
objets, FilterChain
prendrait une collection de pointeurs intelligents à Filter
objets. Lorsque le destructeur FilterChain
est appelé, il détruit les pointeurs intelligents. Le destructeur du pointeur intelligent lui-même détruirait alors l'objet pointé (objet Filter
) si et seulement si le drapeau booléen indiquant la propriété est défini. J'ai l'impression que ce problème est courant en C++, mais ma recherche de solutions populaires ou de modèles de conception intelligents n'a pas très bien réussi. En effet, auto_ptr
n'aide pas vraiment ici et shared_ptr
semble trop. Donc, ma solution est-elle une bonne idée ou pas?
Pourquoi le pointeur partagé est-il trop puissant? C'est beaucoup plus facile que de rouler les vôtres en termes de mise en œuvre immédiate et de maintenance (tout le monde sait exactement de quoi il s'agit). Les frais généraux sont minimes. – Patrick
Le destructeur de classe de base DOIT être virtuel. –
@Patrick: ça me semble trop compliqué car un shared_ptr est un compteur de référence, et j'ai seulement besoin d'un drapeau booléen. –