#ifndef _utl_ShadowPtr_h_ #define _utl_ShadowPtr_h_ #include #include #include namespace utl { /** DV: For some classes (Type) that inherit from an pure abstract base class we can not call a (non-existing) copy constructor, i.e. we can not use new Type(t). The utl::CopyOrClone class does some meta-programming magic and uses copy constructor for normal objects and switches to a virtual copy constructor Clone() static method when it exists. */ namespace ShadowPtrMeta { struct True { }; struct False { char c[256]; }; template True MatchCloneTag(typename T::IsClonableTag* const); template False MatchCloneTag(...); template struct HasClone { static const bool value = sizeof(MatchCloneTag(0)) == sizeof(True); }; template struct BoolSwitch { static T* GetCopy(const T& t) { return new T(t); } }; template struct BoolSwitch { static T* GetCopy(const T& t) { return t.Clone(); } }; /** \brief Clone a given object * * \param src Object to be cloned * \return Pointer to cloned object * * This function exists as a customization point for the ShadowPtr template * for classes which need a special cloning mechanism. If a class \c c is * accompanied by a function c* Clone(const c& src) in the same * namespace, it will get used instead of the this templated function due * to Koenig lookup. * * \note * This mechanism can be used to introduce an indirection for cloning. * Normally, the the compiler has to see the full definition of a class * in order to be able to instantiate the \c Clone template function. If * an overloaded function gets called instead, the instantiation does not * take place. The class specific \c Clone function can be declared in the * header and defined with the rest of the class. This re-enables the use * of forward declarations with shadow pointers, at the price of providing * the class specific \c Clone. */ template T* Clone(const T& src) { return BoolSwitch::value, T>::GetCopy(src); } template T* CloneOne(const T& src) { return Clone(src); } } template class Meta { private: typedef class { } False; typedef class { False f[256]; } True; template static True MatchCloneTag(typename U::IsClonableTag* const); template static False MatchCloneTag(...); template struct HasClone { static const bool value = sizeof(Meta::template MatchCloneTag(0)) == sizeof(True); }; template struct BoolSwitch { static T* GetCopy(const T& t) { return new T(t); } }; template struct BoolSwitch { static T* GetCopy(const T& t) { return t.Clone(); } }; public: static T* GetCopy(const T& t) { return BoolSwitch::value>::GetCopy(t); } }; /** \class ShadowPtr \brief pointer with built-in initialization, deletion, deep copying This class should behave exactly as a simple pointer to a phantom class T except in this cases: -> empty ctor initializes it to 0 -> dtor deletes phantom -> operator= deletes current phantom and makes a deep copy of the phantom argument \author Darko Veberic and Lukas Nellen \version $Id: ShadowPtr.h 17049 2010-06-29 07:51:07Z smueller $ \ingroup stl Motivation: In Offline the event hierarchy (evt::Event) has a simple tree-like structure with data leaves and optional branches containing additional substructures (e.g. starting at the top, evt::Event contains header data evt::Header and several branches (sevt::SEvent, fevt::FEvent etc.)). In general an event may not contain all the branches. For instance, a pure SD event will not contain any of the FD parts. That is why in the parent class the branches are implemented as pointers to the child classes, (should be) initialized to zero if the specific part of the event is missing. Although this is the best of the possible solutions, having pointers in the body of the parent class introduces several drawbacks: - parent's constructor, destructor, copy constructor, and operator= have to be coded by hand - proper initialization and destruction has to be taken care of - const-ness of the parent object is not transparently transferred to the child objects (it has to be maintained artificially through the Set/Get methods) To remedy this highly unmanageable code bloat a templated ShadowPtr class is wrapped around the bare C++ pointers. The InitializedShadowPtr variant also initializes the pointer with new copy of the object by calling the default constructor. Ensuring that the Offline classes contain only data members and shadow pointers there is no need to write default constructors, copy constructors, and operator=. In this way we get rid of a lot of highly unmaintainable and error-prone code that repeats itself only with slight variations in all of the Offline classes. Based on the template definition of the ShadowPtr the compiler will (usually more correctly) generate it for free. */ template class ShadowPtr : public SafeBoolCast > { public: // shallow ctor explicit ShadowPtr(T* const ptr = 0) : fPtr(ptr) { } // deep copy ctor ShadowPtr(const ShadowPtr& shadow) { DeepCopy(shadow.fPtr); } ~ShadowPtr() { Delete(); } T* Get() { return fPtr; } const T* Get() const { return fPtr; } // deep copy assignment ShadowPtr& operator=(const ShadowPtr& shadow) { Delete(); DeepCopy(shadow.fPtr); return *this; } // shallow assignment ShadowPtr& operator=(T* const ptr) { Delete(); fPtr = ptr; return *this; } T& operator*() { DereferenceCheck::Examine(fPtr); return *fPtr; } const T& operator*() const { DereferenceCheck::Examine(fPtr); return *fPtr; } T* operator->() { DereferenceCheck::Examine(fPtr); return fPtr; } const T* operator->() const { DereferenceCheck::Examine(fPtr); return fPtr; } bool operator==(const ShadowPtr& shadow) const { return fPtr == shadow.fPtr; } bool operator!=(const ShadowPtr& shadow) const { return fPtr != shadow.fPtr; } bool operator==(const T* const ptr) const { return fPtr == ptr; } bool operator!=(const T* const ptr) const { return fPtr != ptr; } bool BoolCast() const { return fPtr; } void Swap(ShadowPtr& shadow) { std::swap(fPtr, shadow.fPtr); } private: void Delete() { delete fPtr; } protected: void DeepCopy(const T* const ptr) { fPtr = (ptr ? Meta::GetCopy(*ptr) : 0); } T* fPtr; }; template class InitializedShadowPtr : public ShadowPtr { public: InitializedShadowPtr() : ShadowPtr(new T) { } }; template inline bool DeepEqual(const ShadowPtr& s1, const ShadowPtr& s2) { return (!s1 && !s2) || (s1 && s2 && *s1 == *s2); } /// this helps ShadowPtr in STL containers template inline void swap(ShadowPtr& a, ShadowPtr& b) { a.Swap(b); } } #endif // Configure (x)emacs for this file ... // Local Variables: // mode: c++ // End: