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.
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
#include "RageUtil.h"
|
||||
#include "RageLog.h"
|
||||
|
||||
#include "RageUtil_AutoPtr.h"
|
||||
REGISTER_CLASS_TRAITS( NoteData, new NoteData(*pCopy) )
|
||||
|
||||
NoteData::NoteData()
|
||||
{
|
||||
|
||||
@@ -96,6 +96,103 @@ inline void swap( AutoPtrCopyOnWrite<T> &a, AutoPtrCopyOnWrite<T> &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<class T>
|
||||
struct HiddenPtrTraits
|
||||
{
|
||||
static T *Copy( const T *pCopy );
|
||||
static void Delete( T *p );
|
||||
};
|
||||
#define REGISTER_CLASS_TRAITS(T, CopyExpr) \
|
||||
template<> T *HiddenPtrTraits<T>::Copy( const T *pCopy ) { return CopyExpr; } \
|
||||
template<> void HiddenPtrTraits<T>::Delete( T *p ) { delete p; }
|
||||
|
||||
template<class T>
|
||||
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<T> &cpy )
|
||||
{
|
||||
if( cpy.m_pPtr == NULL )
|
||||
m_pPtr = NULL;
|
||||
else
|
||||
m_pPtr = HiddenPtrTraits<T>::Copy( cpy.m_pPtr );
|
||||
}
|
||||
|
||||
template<class U>
|
||||
HiddenPtr( const HiddenPtr<U> &cpy )
|
||||
{
|
||||
if( cpy.m_pPtr == NULL )
|
||||
m_pPtr = NULL;
|
||||
else
|
||||
m_pPtr = HiddenPtrTraits<U>::Copy( cpy.m_pPtr );
|
||||
}
|
||||
|
||||
~HiddenPtr()
|
||||
{
|
||||
HiddenPtrTraits<T>::Delete( m_pPtr );
|
||||
}
|
||||
void Swap( HiddenPtr<T> &rhs ) { swap( m_pPtr, rhs.m_pPtr ); }
|
||||
|
||||
HiddenPtr<T> &operator=( T *p )
|
||||
{
|
||||
HiddenPtr<T> t( p );
|
||||
Swap( t );
|
||||
return *this;
|
||||
}
|
||||
|
||||
HiddenPtr<T> &operator=( const HiddenPtr &cpy )
|
||||
{
|
||||
HiddenPtr<T> t( cpy );
|
||||
Swap( t );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class U>
|
||||
HiddenPtr<T> &operator=( const HiddenPtr<U> &cpy )
|
||||
{
|
||||
HiddenPtr<T> t( cpy );
|
||||
Swap( t );
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
T *m_pPtr;
|
||||
|
||||
template<class U>
|
||||
friend class HiddenPtr;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
inline void swap( HiddenPtr<T> &a, HiddenPtr<T> &b )
|
||||
{
|
||||
a.Swap(b);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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<NoteData> m_pNoteData;
|
||||
mutable bool m_bNoteDataIsFilled;
|
||||
mutable CString m_sNoteDataCompressed;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user