Arbre shared_ptr et weak_ptr
Bonjour tout le monde,
Je suis en train de construire un petit arbre basé sur les pointeurs intelligents.
J'ai mon objet (Node) contenant un std::weak_ptr pour son parent et une liste de std::weak_ptr pour ses enfants.
Ces différents objets sont stocker dans un conteneur me permettant d'accéder plus facilement aux différents noeuds.
Je souhaite :
- lorsque je supprime le parent de supprimer tous les enfants
- lorsque je supprime un enfant, il soit supprimer de son parent
Pour résoudre le 1), j'envoie un évènement pour dire à mon conteneur de supprimer le noeud.
Pour résoudre le 2), je demande au parent de parcourir toute la liste des enfants et de supprimer les enfants déjà supprimés.
Je voulais savoir si quelqu'un à une autre approche à me proposer (dont éviter de parcourir toute la liste des enfants pour supprimer ceux déjà supprimés).
Merci.
Voici un exemple d'implémentation de mon idée (sans la partie conteneur d'objet ni envoie d'évènement pour supprimer les enfants lors de la suppression du parent):
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 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
| #include <memory>
#include <list>
#include <iostream>
using namespace std;
class Node;
typedef std::shared_ptr<Node> NodePtr;
typedef std::weak_ptr<Node> NodeWPtr;
class Node : public std::enable_shared_from_this<Node>
{
friend class NodeFactory;
Node() = default;
public:
virtual ~Node()
{
if (NodePtr p = p_parent.lock()) {
p->removeDeletedChild();
}
for (NodeWPtr c : p_children) {
if (NodePtr child = c.lock()) {
// TODO: ajouter l'évènement pour demander au conteneur de supprimer child
child->p_parent.reset();
}
}
}
void addChild(NodePtr child)
{
if (child) {
child->p_parent = getPtr();
// child est converti automatiquement en weak_ptr;
p_children.push_back(child);
}
}
const std::list<NodeWPtr> & getChildren() const
{
return p_children;
}
void removeDeletedChild()
{
std::list<NodeWPtr>::iterator it;
for (it = p_children.begin(); it != p_children.end();) {
NodePtr child = it->lock();
if (!child) {
it = p_children.erase(it);
} else {
++it;
}
}
}
NodePtr getPtr()
{
return shared_from_this();
}
protected:
NodeWPtr p_parent;
std::list<NodeWPtr> p_children;
};
class NodeFactory
{
public:
NodePtr create()
{
return std::shared_ptr<Node>(new Node());
}
};
int main()
{
NodeFactory factory;
NodePtr parent = factory.create();
NodePtr child1 = factory.create();
NodePtr child2 = factory.create();
parent->addChild(child1);
parent->addChild(child2);
if (parent->getChildren().size() != 2) {
std::cerr << "Problem to add children" << std::endl;
return 1;
} else {
NodeWPtr tmpWChild1 = parent->getChildren().front();
NodeWPtr tmpWChild2 = parent->getChildren().back();
if (NodePtr tmpChild1 = tmpWChild1.lock()) {
if (tmpChild1 != child1) {
std::cerr << "tmpChild1 is different from child1" << std::endl;
return 1;
}
} else {
std::cerr << "The child1 is not added correctly" << std::endl;
return 1;
}
if (NodePtr tmpChild2 = tmpWChild2.lock()) {
if (tmpChild2 != child2) {
std::cerr << "tmpChild2 is different from child1" << std::endl;
return 1;
}
} else {
std::cerr << "The child2 is not added correctly" << std::endl;
return 1;
}
child2.reset();
if (parent->getChildren().size() != 1) {
std::cerr << "Problem to remove children" << std::endl;
return 1;
} else {
tmpWChild1 = parent->getChildren().front();
if (NodePtr tmpChild1 = tmpWChild1.lock()) {
if (tmpChild1 != child1) {
std::cerr << "tmpChild1 is different from child1" << std::endl;
return 1;
}
} else {
std::cerr << "The child1 is not added correctly" << std::endl;
return 1;
}
}
}
std::cout << "All work correctly" << std::endl;
return 0;
} |