back_ref.C

00001 #include <string>
00002 #include <iostream>
00003 
00004 #include <archon/util/exception.H>
00005 #include <archon/util/ref.H>
00006 
00007 using namespace std;
00008 using namespace Archon::Utilities;
00009 
00010 
00011 /*
00012 
00013 Garbage Collection:
00014 -------------------
00015 
00016 Using the smart pointer 'Ref' is an approach to garbage collection. It
00017 solves a "local" problem of deallocating an object when there is no
00018 more _imadiate_ references to it anymore. It leaves a global problem
00019 though: To make sure that no cyclic reference chains are ever
00020 introduced.
00021 
00022 Even though we are able to cope with a restricted use of cyclic
00023 references (by breaking the cycles forcefully), it still remains for
00024 the user to ensure that the references are only used in that
00025 restricted manner.
00026 
00027 An alternative to using smart pointers, would be to use objects that
00028 when "visited" knows how to recursivly visit all the objects that the
00029 first object refers to. Proberbly via a virtual function 'visit'. Then
00030 we have to maintain a set of root pointers and once in a while we
00031 should visit all root pointers and mark all the objects that gets
00032 visited. All objects that are not visited in this process may be
00033 deleted. This is the way SpiderMonkey does it. This startegy does not
00034 suffer from the cyclic renference problem and thus has a great
00035 advantage there. It still leaves a global problem though, we have to
00036 write a new correct 'visit' method for every new class. Also we have
00037 to considder data protection between the garbage collection thread and
00038 the other threads in action. This methos has two other disadvantages
00039 it takes up CPU time to do the visiting, and it takes up more memory,
00040 since objects are not deallocated as soon as possible, On the other
00041 hand, copying references may be faster since we do not need to adjust
00042 a reference count. A problem would also be that we cannot hold a
00043 single pointer on the stack, cause there is no way to discover that.
00044 The sollution is to root the pointer.
00045 
00046 */
00047 
00048 /*
00049 
00050 Considder an asyclic directed graph of objects with smart pointers to
00051 other objects. This includes a set of root pointers held by one or
00052 more outside parties. Such a graph will have the property that every
00053 object in it will be deleted if all the root pointers are
00054 deleted. This property af cource is important to prevent memory leak.
00055 
00056 We also want every element to have a unique static reference to its
00057 container. With is almoast the same as saying that the container must
00058 always be available to its elements. This suggests the root the Server
00059 will be deleted when every Context is deleted, which in
00060 turn will happen when every node belonnging to that context is
00061 deleted. In other words, the destruction will happen from leafs to the
00062 root.
00063 
00064 Imagine that some of these objects have the logical role of being a
00065 container for some or all of the objects that it refers to.
00066 
00067 Then it will often be desirable to add a reference from each of the
00068 contained
00069 
00070 
00071 There is a static link from an element to its container.
00072 
00073 Elements may refer to other elements.
00074 There is a root element.
00075 
00076 The idea is that calling 'clear' on a ContainerRefObjectBase must
00077 eventually lead to its destruction due to the death of all its
00078 children.
00079 
00080 */
00081 
00082 /*
00083 
00084 A directed acyclic graph is similar to a tree directed from root to
00085 leafs except that it may have several roots. Take this to be the
00086 definition of the concept of leafs and roots in a directed acyclic
00087 graph.
00088 
00089 A forward reference is then a reference going in the direction from
00090 the roots to the leafs, and a backward reference is a reference going
00091 in the direction from the leafs to the roots.
00092 
00093 */
00094 
00095 namespace
00096 {
00097   struct Node;
00098 
00099   struct Route: RefObjectBase
00100   {
00101     const BackRef<Node> node;
00102 
00103     Route(BackRef<Node> node): node(node) {}
00104 
00105     ~Route() { cerr << "~Route\n"; }
00106   };
00107 
00108   struct Context;
00109 
00110   struct Node: BackRefObjectBase
00111   {
00112     const BackRef<Context> context;
00113 
00114     Ref<Route> route;
00115 
00116     Node(BackRef<Context> context): context(context) {}
00117 
00118     ~Node() { cerr << "~Node\n"; }
00119 
00120     void refForwardDestroy()
00121     {
00122       route.reset();
00123     }
00124   };
00125 
00126   struct Server;
00127 
00128   struct Context: BackRefObjectBase
00129   {
00130     const BackRef<Server> server;
00131 
00132     Ref<Node> node;
00133 
00134     Context(BackRef<Server> server): server(server) {}
00135 
00136     ~Context() { cerr << "~Context\n"; }
00137 
00138     void refForwardDestroy()
00139     {
00140       node.reset();
00141     }
00142   };
00143 
00144   struct Server: BackRefObjectBase
00145   {
00146     Ref<Context> context;
00147 
00148     ~Server() { cerr << "~Server\n"; }
00149 
00150     void refForwardDestroy()
00151     {
00152       context.reset();
00153     }
00154   };
00155 }
00156 
00157 
00158 int main()
00159 {
00160   set_unexpected(Exception::terminal<exceptionCatchInfo>);
00161   set_terminate (Exception::terminal<exceptionCatchInfo>);
00162 
00163   Ref<Server> server = new Server;
00164   Ref<Context> context = new Context(server);
00165   Ref<Node> node = new Node(context);
00166   Ref<Route> route = new Route(node);
00167 
00168   node->route = route;
00169   context->node = node;
00170   server->context = context;
00171 
00172   return 0;
00173 }

Generated on Sun Jul 30 22:55:43 2006 for Archon by  doxygen 1.4.4