Activer et désactiver la propriété Retournons sur le problème de propriété. Les conteneurs qui stockent les objets par valeur se moquent normalement de la propriété parce qu'ils possèdent clairement l'objet qu'ils contiennent. Mais si votre conteneur stocke des pointeurs (ce qui est plus courant en C++, spécialement avec le polymorphisme), il est alors probable que ces pointeurs soient aussi utilisés autre part dans le programme, et vous n'avez pas nécessairement intérêt à supprimer l'objet parce qu'alors les autres pointeurs dans le programme référenceraient un objet détruit. Pour éviter cela, vous devez utilisez la propriété quand vous concevez et utilisez un conteneur. Beaucoup de programmes sont plus simples que cela et ne rencontrent pas le problème de propriété : un conteneur stocke des pointeurs sur des objets qui sont utilisés uniquement par ce conteneur. Dans ce cas la propriété est vraiment simple : le conteneur possède ses objets. La meilleure approche pour gérer le problème de propriété est de donner un choix au programmeur client. C'est souvent accompli par un argument du constructeur qui indique par défaut la propriété (cas le plus simple). En outre il peut y avoir des fonctions “get” (dans le sens de voir, ndt) et “set” (fixer, ndt) pour voir et modifier la propriété du conteneur. Si le conteneur a des fonctions pour supprimer un objet, l'état de propriété affecte généralement cette suppression, et vous pouvez donc trouver des options pour contrôler la destruction dans la fonction de suppression. On peut concevoir que vous puissiez ajouter une donnée de propriété pour chaque élément dans le conteneur, de telle qorte que chaque position saurait si elle doit être détruite ; c'est une variante du compteur de référence, excepté que le conteneur et non l'objet connaît le nombre de références pointant sur un objet. //: C16:OwnerStack.h // Stack avec contrôle de propriété à l'exécution #ifndef OWNERSTACK_H #define OWNERSTACK_H template<class T> class Stack { struct Link { T* data; Link* next; Link(T* dat, Link* nxt) : data(dat), next(nxt) {} }* head; bool own; public: Stack(bool own = true) : head(0), own(own) {} ~Stack(); void push(T* dat) { head = new Link(dat,head); } T* peek() const { return head ? head->data : 0; } T* pop(); bool owns() const { return own; } void owns(bool newownership) { own = newownership; } // Auto-conversion de type : vrai si pas vide : operator bool() const { return head != 0; } }; template<class T> T* Stack<T>::pop() { if(head == 0) return 0; T* result = head->data; Link* oldHead = head; head = head->next; delete oldHead; return result; } template<class T> Stack<T>::~Stack() { if(!own) return; while(head) delete pop(); } #endif // OWNERSTACK_H ///:~ Le comportement par défaut pour le conteneur est qu'il détruit ses objets mais vos pouvez le changer soit en modifiant l'argument du constructeur soit en utilisant les fonctions membres de lecture/écriture owns( ). Comme avec le plus grand nombre de templates que vous êtes susceptibles de voir, toute l'implémentation est contenue dans le fichier d'entête. Voici un petit test qui applique les possibilités de la propriété : //: C16:OwnerStackTest.cpp //{L} AutoCounter #include "AutoCounter.h" #include "OwnerStack.h" #include "../require.h" #include <iostream> #include <fstream> #include <string> using namespace std; int main() { Stack<AutoCounter> ac; // Propriété activée Stack<AutoCounter> ac2(false); // Désactive la propriété AutoCounter* ap; for(int i = 0; i < 10; i++) { ap = AutoCounter::create(); ac.push(ap); if(i % 2 == 0) ac2.push(ap); } while(ac2) cout << ac2.pop() << endl; // Pas de destruction nécessaire puisque // ac "possède" tous les objets } ///:~ L'objet ac2 ne possède pas les objets que vous mettez dedans, ainsi ac est le conteneur “maître” qui prend la responsabilité de la propriété. Si, à un moment quelconque de la durée de vie du conteneur, vous voulez changer l'état de propriété des objets par le conteneur (le rendre propriétaire ou bien faire cesser sa propriété), vous pouvez le faire en utilisant owns( ). Il serait aussi possible aussi de changer la granularité de la propriété afin qu'elle soit sur une base de relation d'objet à objet, mais cela rendra probablement la solution au problème de propriété plus complexe que le problème lui-même.