From f2a418d79d97ac8618ad04e22e388c3a871c79e8 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Sun, 3 Jul 2005 03:05:54 +0000 Subject: [PATCH] implement HiddenPtr smart pointer type; use it for Steps. This avoids having to write a whole copy constructor for a class just to hide a couple types from the header. --- stepmania/src/NoteData.cpp | 2 + stepmania/src/RageUtil_AutoPtr.h | 97 ++++++++++++++++++++++++++++++++ stepmania/src/Steps.cpp | 2 +- stepmania/src/Steps.h | 3 +- 4 files changed, 102 insertions(+), 2 deletions(-) diff --git a/stepmania/src/NoteData.cpp b/stepmania/src/NoteData.cpp index 390df26af7..4a584f8a62 100644 --- a/stepmania/src/NoteData.cpp +++ b/stepmania/src/NoteData.cpp @@ -9,6 +9,8 @@ #include "RageUtil.h" #include "RageLog.h" +#include "RageUtil_AutoPtr.h" +REGISTER_CLASS_TRAITS( NoteData, new NoteData(*pCopy) ) NoteData::NoteData() { diff --git a/stepmania/src/RageUtil_AutoPtr.h b/stepmania/src/RageUtil_AutoPtr.h index c841dff828..3c821e1b18 100644 --- a/stepmania/src/RageUtil_AutoPtr.h +++ b/stepmania/src/RageUtil_AutoPtr.h @@ -96,6 +96,103 @@ inline void swap( AutoPtrCopyOnWrite &a, AutoPtrCopyOnWrite &b ) a.Swap(b); } +/* + * This smart pointer template is used to safely hide implementations from + * headers, to reduce dependencies. This is the same as declaring a pointer + * to a class, and allocating/deallocating it in the implementation: only + * the implementation needs to include that class. This makes copying + * and deletion automatic, so you don't need to include a copy ctor or + * remember to delete it. + * + * There's one subtlety: in order to copy or delete an object, we need its + * definition. This is intended to avoid pulling in the definition. So, + * we use a traits class to hide it. Use REGISTER_CLASS_TRAITS for each + * class used with this template. + * + * Concepts from http://www.gotw.ca/gotw/062.htm. + */ +template +struct HiddenPtrTraits +{ + static T *Copy( const T *pCopy ); + static void Delete( T *p ); +}; +#define REGISTER_CLASS_TRAITS(T, CopyExpr) \ + template<> T *HiddenPtrTraits::Copy( const T *pCopy ) { return CopyExpr; } \ + template<> void HiddenPtrTraits::Delete( T *p ) { delete p; } + +template +class HiddenPtr +{ +public: + const T& operator*() const { return *m_pPtr; } + const T* operator->() const { return m_pPtr; } + T& operator*() { return *m_pPtr; } + T* operator->() { return m_pPtr; } + + explicit HiddenPtr( T *p = NULL ) + { + m_pPtr = p; + } + + HiddenPtr( const HiddenPtr &cpy ) + { + if( cpy.m_pPtr == NULL ) + m_pPtr = NULL; + else + m_pPtr = HiddenPtrTraits::Copy( cpy.m_pPtr ); + } + + template + HiddenPtr( const HiddenPtr &cpy ) + { + if( cpy.m_pPtr == NULL ) + m_pPtr = NULL; + else + m_pPtr = HiddenPtrTraits::Copy( cpy.m_pPtr ); + } + + ~HiddenPtr() + { + HiddenPtrTraits::Delete( m_pPtr ); + } + void Swap( HiddenPtr &rhs ) { swap( m_pPtr, rhs.m_pPtr ); } + + HiddenPtr &operator=( T *p ) + { + HiddenPtr t( p ); + Swap( t ); + return *this; + } + + HiddenPtr &operator=( const HiddenPtr &cpy ) + { + HiddenPtr t( cpy ); + Swap( t ); + return *this; + } + + template + HiddenPtr &operator=( const HiddenPtr &cpy ) + { + HiddenPtr t( cpy ); + Swap( t ); + return *this; + } + +private: + T *m_pPtr; + + template + friend class HiddenPtr; +}; + +template +inline void swap( HiddenPtr &a, HiddenPtr &b ) +{ + a.Swap(b); +} + #endif /* diff --git a/stepmania/src/Steps.cpp b/stepmania/src/Steps.cpp index 35406da56d..0b32522a88 100644 --- a/stepmania/src/Steps.cpp +++ b/stepmania/src/Steps.cpp @@ -16,6 +16,7 @@ #include "global.h" #include "Steps.h" #include "StepsUtil.h" +#include "song.h" #include "RageUtil.h" #include "RageLog.h" #include "NoteData.h" @@ -41,7 +42,6 @@ Steps::Steps() Steps::~Steps() { - delete m_pNoteData; } void Steps::SetNoteData( const NoteData& noteDataNew ) diff --git a/stepmania/src/Steps.h b/stepmania/src/Steps.h index f55fe5a311..3e9d0aa5d6 100644 --- a/stepmania/src/Steps.h +++ b/stepmania/src/Steps.h @@ -8,6 +8,7 @@ #include "Grade.h" #include "RadarValues.h" #include "Difficulty.h" +#include "RageUtil_AutoPtr.h" class Profile; class NoteData; struct lua_State; @@ -76,7 +77,7 @@ protected: /* We can have one or both of these; if we have both, they're always identical. * Call Compress() to force us to only have m_sNoteDataCompressed; otherwise, creation of * these is transparent. */ - mutable NoteData *m_pNoteData; + mutable HiddenPtr m_pNoteData; mutable bool m_bNoteDataIsFilled; mutable CString m_sNoteDataCompressed;