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 }