summaryrefslogtreecommitdiff
path: root/utils/SmartPointer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'utils/SmartPointer.cc')
-rw-r--r--utils/SmartPointer.cc245
1 files changed, 245 insertions, 0 deletions
diff --git a/utils/SmartPointer.cc b/utils/SmartPointer.cc
new file mode 100644
index 0000000..264a7e1
--- /dev/null
+++ b/utils/SmartPointer.cc
@@ -0,0 +1,245 @@
+/*
+ * CENA C++ Utilities
+ *
+ * by Stephane Chatty
+ *
+ * Copyright 1990, 1991, 1992
+ * Laboratoire de Recherche en Informatique (LRI)
+ * Centre d'Etudes de la Navigation Aerienne (CENA)
+ *
+ * smart pointers, originally by Michel Beaudouin-Lafon
+ *
+ * $Id$
+ * $CurLog$
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "SmartPointer.h"
+
+CcuSmartData::check_type CcuSmartData::check = Warn;
+int CcuSmartData::NextCreatedIsDynamic = 0;
+
+/*?class CcuSmartData
+The class \typ{CcuSmartData} is the base class for objects that you want to reference through smart pointers.
+Such an object contains a reference count.
+This reference count contains the number of smart pointers to this object.
+When that number reaches 0 and the object was allocated dynamically, it is safe to destroy it
+(unless there are still plain pointers to it!).
+Hence, a \typ{CcuSmartData} destroys itself when its reference count reaches 0
+and it was allocated dynamically (ie. with \fun{operator new}).
+
+To implement the reference counting properly, it is necessary to overload the assignment operator on
+the reference count, so that when object \var{a} is assigned to object \var{b},
+the reference count of \var{b} does not change.
+This means that all classes deriving from \typ{CcuSmartData} will have their assignment operator implicitly redefined.
+This implies a small run-time overhead, and a special care if you need to overload this operator
+in a derived class of \typ{CcuSmartData}.
+
+Another point needs special attention. The only way of deciding whether an object was dynamically
+allocated is to redefine \fun{operator new}. This was done in \typ{CcuSmartData}. However, you might
+want to define your own \fun{new} and \fun{delete} in derived classes. If you do so, you
+should take care that \fun{new} sets the flag \var{CcuSmartData::NextCreatedIsDynamic} to a non-null value.
+?*/
+
+void*
+CcuSmartData :: operator new (unsigned size)
+{
+ NextCreatedIsDynamic = 1;
+ return ::operator new (size);
+}
+
+/*?
+Create a data, ie. initialize its reference count to 0.
+?*/
+CcuSmartData :: CcuSmartData ()
+: State (NextCreatedIsDynamic ? 0 : 1)
+{
+ NextCreatedIsDynamic = 0;
+}
+
+/*?
+This is the copy constructor for the class \typ{CcuSmartData}.
+Because there is a copy constructor defined,
+all derived class will have a copy constructor defined implicitly,
+unless you specify one explicitely.
+?*/
+CcuSmartData :: CcuSmartData (const CcuSmartData&)
+: State (NextCreatedIsDynamic ? 0 : 1)
+{
+ NextCreatedIsDynamic = 0;
+}
+
+/*?
+This is the destructor for class \typ{CcuSmartData}. It is {\em virtual}.
+This destructor checks that the deleted object has a null reference count.
+If not, it notifies the user according to the sanity check value defined with
+the static member function \fun{SetCheck}.
+Dynamically allocated \typ{CcuSmartData} objects are automatically deleted by the smart pointer package
+when their reference count reaches zero.
+?*/
+CcuSmartData :: ~CcuSmartData ()
+{
+ if (State > 1) {
+ if (check >= OnlyDynamic) {
+ if (IsDynamic ())
+ fprintf (stderr, "*** ~CcuSmartData (0x%x) : ref count of dynamic object is %d !\n", this, int (State/2));
+ else if (check >= Warn)
+ fprintf (stderr, "*** ~CcuSmartData (0x%x) : ref count of global or automatic object is %d !\n", this, int (State/2));
+ }
+ if (check == Abort) {
+ fprintf (stderr, "*** aborting\n");
+ abort ();
+ }
+ }
+}
+
+
+void
+CcuSmartData :: DecrRef ()
+{
+ if (----State == 0)
+ delete this;
+}
+
+#ifdef DOC
+/*?
+This protected member returns 1 if this object was allocated with \fun{operator new}.
+?*/
+int
+CcuSmartData :: IsDynamic () const
+{
+}
+#endif
+
+
+/*?
+This {\em static} member controls the sanity check done by the destructor of class \typ{CcuSmartData}:
+a \typ{CcuSmartData} should not be destroyed when its refcount is non zero, because this means
+that some smart pointers are still pointing at it.
+Such errors can happen in two situations:\\
+ \hspace*{0.5cm}1. when calling explicitely \fun{operator delete} on an object that has smart pointers to it;\\
+ \hspace*{0.5cm}2. when a local object (an object on the stack) that has smart pointers to it is automatically
+destroyed upon exit of its enclosing block.\\
+\vspace{0.5ex}
+When an error occurs, the value of \var{chk} defines what happens, as follows:\\
+ \hspace*{0.5cm}$\bullet$ if \var{t} is \var{Warn}, a message is issued on \var{stderr} and processing continues;\\
+ \hspace*{0.5cm}$\bullet$ if \var{t} is \var{Abort}, a message is issued and and \fun{abort} is called, forcing a core dump;\\
+but not for dynamically allocated objects.\\
+ \hspace*{0.5cm}$\bullet$ if \var{t} is \var{OnlyDynamic}, checking is disabled for global and automatic objects,
+ \hspace*{0.5cm}$\bullet$ if \var{t} is \var{NoCheck}, checking is disabled.\\
+\fun{SetCheck} returns the previous value of the checking status.
+The initial value is 0 (warning message).
+?*/
+CcuSmartData::check_type
+CcuSmartData :: SetCheck (check_type t)
+{
+ check_type old = check;
+ check = t;
+ return old;
+}
+
+/*?class CcuSmartPointerTo
+The class \typ{CcuSmartPointerTo} is the smart pointer class itself.
+A \typ{CcuSmartPointerTo} object contains a pointer to a \typ{DATA} object.
+?*/
+
+#ifdef DOC
+
+/*?
+Construct a null smart pointer.
+?*/
+CcuSmartPointerTo :: CcuSmartPointerTo ()
+{
+}
+
+/*?
+Construct a smart pointer to data \var{d}.
+\var{d} may be 0.
+?*/
+CcuSmartPointerTo :: CcuSmartPointerTo (DATA* d)
+{
+}
+
+/*?
+This is the copy constructor for smart pointers.
+It ensures that the reference counts are properly updated when a smart pointer
+is initialized by copy (argument passing and function return for instance).
+?*/
+CcuSmartPointerTo :: CcuSmartPointerTo (const CcuSmartPointerTo& p)
+{
+}
+
+/*?
+The destructor updates the reference count of the pointed to data,
+and destroys it if the reference count reaches 0 and the data was dynamically allocated.
+?*/
+CcuSmartPointerTo :: ~CcuSmartPointerTo ()
+{
+}
+
+/*?
+This operator overloads the assignment of smart pointers.
+It can destroy the data pointed by the left-hand side pointer if its reference count reaches 0.
+?*/
+CcuSmartPointerTo&
+CcuSmartPointerTo :: operator = (const DATA* d)
+{
+}
+
+/*?
+This operator overloads the dereferencing of smart pointers.
+Unfortunately, it returns a \typ{DATA*} where one would prefer a pointer to a derived class of \typ{DATA}.
+This problem, which occurs also with the overloading operators below,
+is fixed by the generic pointer class (\fun{PointerClass}) described below.
+?*/
+DATA*
+CcuSmartPointerTo :: operator -> ()
+{
+}
+
+/*?
+These conversion operators make it possible to pass a pointer to data where a smart pointer is expected.
+They also make it possible to test a smart pointer like a usual pointer.
+?*/
+CcuSmartPointerTo :: operator DATA* ()
+{
+}
+
+// note: this is hacked up for the doc stuff
+/*?
+This is a macro to generate a smart pointer class.
+\typ{SmartClass} is the name of the class to generate,
+and \typ{DataClass} is the name of the class to which \typ{SmartClass} objects will point.
+\typ{DataClass} must derive from \typ{DATA}.
+The generated class is similar to the class \typ{CcuSmartPointerTo} described above,
+with \typ{CcuSmartPointerTo} replaced by \typ{SmartClass} and \typ{DATA} replaced by \typ{DataClass}.
+In particular, this means that such smart pointers can be dereferenced with the \fun{operator ->}
+like usual pointers.
+?*/
+generic
+PointerClass (SmartClass, DataClass)
+{
+}
+
+/*?
+This macro is similar to \fun{PointerClass} described above.
+It generates a smart pointer class named \typ{SmartClass}
+for the class \typ{DataClass}.
+Unlike the previous macro, the generated class is not a base class,
+but instead a derived class of \typ{SmartBaseClass},
+which must be a smart pointer class itself.
+If \typ{pA} is a smart pointer class to class \typ{A} and \typ{B} derives from \typ{A},
+you can declare a smart pointer class \typ{pB} to the class \typ{B} with:\\
+\hspace*{1cm}\com{DerivedPointerClass (pB, pA, A)}\\
+Then \typ{pB} objects can be used where \typ{pA} objects are expected,
+which would not be the case if \typ{pB} was declared with \fun{PointerClass}.
+?*/
+generic
+DerivedPointerClass (SmartClass, BaseSmartClass, DataClass)
+{
+}
+
+#endif
+