From 3a4838bed13b767132cbdf06364b2658da6cc356 Mon Sep 17 00:00:00 2001 From: chatty Date: Tue, 15 Dec 1992 10:55:33 +0000 Subject: Initial revision --- utils/SmartPointer.cc | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 utils/SmartPointer.cc (limited to 'utils/SmartPointer.cc') 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 +#include + +#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 + -- cgit v1.1