- xonorptrs_demo.zip
- SPointers
- res
- cur00001.cur
- cur00002.cur
- cur00003.cur
- cur00004.cur
- cur00005.cur
- cur00006.cur
- cur00007.cur
- cursor1.cur
- cursor2.cur
- mainfram.bmp
- SPointers.ico
- toolbar.bmp
- toolbar1.bmp
- SPointers.sln
- SPointers
- XonorPtrs..dgm
- xonorptrs_src.zip
- XonorPtrs_Src
|
#pragma once
class critical_section :
public CRITICAL_SECTION
{
public:
critical_section()
{
::InitializeCriticalSection( this );
}
~critical_section()
{
::DeleteCriticalSection( this );
}
// Acquire the critical section
void Enter()
{
::EnterCriticalSection( this );
}
// Release the critical section
void Leave()
{
::LeaveCriticalSection( this );
}
};
/*****************************************************************************************
Turn on monitoring in debug mode
******************************************************************************************/
#ifdef _DEBUG
#define MONITOR_REF_CONTROLERS
#define MONITOR_PTRS
#define VERIFY_INTEGRITY
#endif
#ifdef MONITOR_PTRS
#define MONITOR_REF_CONTROLERS
#endif
/*****************************************************************************************
By default this system protects against class slicing and it is not necessary that
base class destructors are declared virtual. xvirtual is defined as nothing. This protection
incurs an extra overhead of two pointer values per reference controler.
If you are confident that you always use virtual destructors in polymorphic base classes then
place the following just above #include <ZonorPtrs.h> in your project
#define I_ALWAYS_USE_VIRTUAL_DESTRUCTORS_IN_POLYMORPHIC_BASE_CLASSES
This will switch off the protection against class slicing and will also define xvirtual as
virtual.
Use xvirtual to qualify polymorphic base class destructors so that they are only declared
virtual when I_ALWAYS_USE_VIRTUAL_DESTRUCTORS_IN_POLYMORPHIC_BASE_CLASSES is defined.
******************************************************************************************/
#ifdef I_ALWAYS_USE_VIRTUAL_DESTRUCTORS_IN_POLYMORPHIC_BASE_CLASSES
#define xvirtual virtual
#else
#define xvirtual
#endif
namespace XonorPtrs {
/*****************************************************************************************
Forward declarations
******************************************************************************************/
template <class T, bool t_bDelete=true> class owner_ptr;//Scoped pointer that owns and deletes the object
template <class T> class owner_ptr_base;
template <class T> class ref_pointer_base;
template <class T> class new_ptr;
template <class T> class ref_ptr;//A general purpose weak reference, suitable for class members
template <class T> class fast_ptr;//A full speed pointer to use within a code block
template <class T> class enable_ref_ptr_to_this;//An add-in templated base class which allows class to ref_ptr and fast_ptr pointers to this
template <class T> class strong_ptr;//A classic strong or shared pointer.
/*************************************************************************************************
class xonor_ptr_exception - recoverable exception class - to be thrown when no other defined
behavior is possible. Typically these are throw when trying to dereference a NULL pointer
where throwing an exception is the only possible action. Although it is not a good practice
you can handle these execptions and continue execution. Generally they indicate that you have ommited
a test for NULL which you should correct.
***************************************************************************************************/
class xonor_ptr_exception
{
CString m_csReason;
public:
xonor_ptr_exception(CString csReason)
{
m_csReason=csReason;
};
~xonor_ptr_exception() {};
const TCHAR *ShowReason() const
{
return m_csReason;
}
};
/*************************************************************************************************
class xonor_ptr_fatal_exception - non-recoverable exception class - to be thrown when no
continuation of execution is a bad idea.
IMPORTANT - This is a stop the program' exception you should NEVER handle it and continue execution.
Some of these exceptions are thrown during construction and destruction and therefore any attempt to
continue execution is going to be messy. This exception throwing pattern is NOT designed for run-time
recovery. If you are getting these exceptions you have a serious coding error and you must correct it.
***************************************************************************************************/
class xonor_ptr_fatal_exception
{
CString m_csReason;
public:
xonor_ptr_fatal_exception(CString csReason)
{
m_csReason=csReason;
};
~xonor_ptr_fatal_exception() {};
const TCHAR *ShowReason() const
{
return CString(_T("FATAL exception"))+m_csReason;
}
};
/*****************************************************************************************
T* down_cast(U* pU) a discriminating downcaster of raw pointers.
******************************************************************************************/
template<class T, class U>
inline T* down_cast(U* pU)
{
if(sizeof(T)>sizeof(U))
throw xonor_ptr_fatal_exception(_T("Not a downcast"));
return static_cast<T*>(pU);
}
namespace PRIVATE{
template <class T> class reference_controler_impl;
const int BlockSize=100;
const int NumBlocks=100;
class reference_controler
{
//*************************************************************************************************
//Holds pointer and ref_ptr counts - created on the heap when a first
//reference is taken and self destructs when no references remain
//************************************************************************************************
public:
#ifdef MONITOR_PTRS
static void SetMonitorOutput(CString& csString)
{
int Tot1=stm_owner_ptr_count*2+stm_ref_ptr_count*2+stm_strong_ptr_count*2+stm_reference_controller_count*2;
int Tot2=stm_owner_ptr_count*2+stm_ref_ptr_count*2+stm_strong_ptr_count*2+stm_reference_controller_count*4;
int Tot=stm_owner_ptr_count+stm_ref_ptr_count+stm_strong_ptr_count;
int PerCent1=100*Tot1/Tot;
int PerCent2=100*Tot2/Tot;
#ifdef I_ALWAYS_USE_VIRTUAL_DESTRUCTORS_IN_POLYMORPHIC_BASE_CLASSES
csString.Format(_T("owner=%4d ref=%4d strong=%4d r.conts.=%4d total xptrs=%4d xptr mem=%4d ptrs %%ratio=%4d"),
stm_owner_ptr_count, stm_ref_ptr_count, stm_strong_ptr_count,
stm_reference_controller_count, stm_owner_ptr_count+stm_ref_ptr_count+stm_strong_ptr_count,
Tot1,
PerCent1 );
#else
csString.Format(_T("owner=%4d ref=%4d strong=%4d r.conts.=%4d total xptrs=%4d xptr mem=%4d ptrs %%ratio=%4d"),
stm_owner_ptr_count, stm_ref_ptr_count, stm_strong_ptr_count,
stm_reference_controller_count, stm_owner_ptr_count+stm_ref_ptr_count+stm_strong_ptr_count,
Tot2,
PerCent2);
#endif
}
#endif
template <class memory_slot>
class reference_controler_pool_base
{
protected:
int m_CurrentBlockSize;
class critical_section_lock
{
critical_section* m_pCriticalSection;
public:
critical_section_lock(critical_section* pCriticalSection)
{
m_pCriticalSection=pCriticalSection;
m_pCriticalSection->Enter();
}
~critical_section_lock()
{
m_pCriticalSection->Leave();
}
};
class memory_block
{
public:
int m_BlockSize;
memory_slot* m_pMemorySlots;
memory_slot* m_pFirstFreeSlot;
memory_block(int ThisBlockSize)
{
m_BlockSize=ThisBlockSize;
m_pMemorySlots=new memory_slot[m_BlockSize];
m_pFirstFreeSlot=m_pMemorySlots;
(m_pMemorySlots+m_BlockSize-1)->m_Next=0;
}
~memory_block()
{
delete [] m_pMemorySlots;
}
memory_slot* give_free_slot()
{
if(NULL==m_pFirstFreeSlot)
return NULL;
memory_slot* p=m_pFirstFreeSlot;
if(p->m_Next!=0)
m_pFirstFreeSlot=p+p->m_Next;
else
m_pFirstFreeSlot=NULL;
return p;
}
void recover_free_slot(memory_slot* p)
{
if(m_pFirstFreeSlot!=NULL)
{
int offset=m_pFirstFreeSlot-p;
if(offset>m_BlockSize || offset<-m_BlockSize)
{
int BreakHere=0;
}
p->m_Next=offset;
}
else
p->m_Next=0;
m_pFirstFreeSlot=p;
}
};
critical_section m_CriticalSection;
memory_block* MemoryBlocks[NumBlocks];
int m_CurrentBlock;
public:
reference_controler_pool_base()
{
m_CurrentBlock=0;
m_CurrentBlockSize=BlockSize;
MemoryBlocks[0]=new memory_block(m_CurrentBlockSize);
m_CurrentBlockSize=(int)(1.1*(double)m_CurrentBlockSize);
}
~reference_controler_pool_base()
{
int Block=0;
memory_block* pBlock=0;
while((pBlock=MemoryBlocks[Block++])!=NULL)
{
delete pBlock;
}
}
void delete_reference_controler(reference_controler* p)
{
p->reference_controler::~reference_controler();
critical_section_lock lock(&m_CriticalSection);
memory_block* pBlock=MemoryBlocks[m_CurrentBlock];
if((memory_slot*)p>=pBlock->m_pMemorySlots && (memory_slot*)p<=pBlock->m_pMemorySlots+m_CurrentBlockSize)
{
pBlock->recover_free_slot((memory_slot*)p);
return;
}
m_CurrentBlock=0;
while(m_CurrentBlock<NumBlocks)
{
memory_block* pBlock=MemoryBlocks[m_CurrentBlock];
if(NULL==pBlock)
break;
if((memory_slot*)p>=pBlock->m_pMemorySlots && (memory_slot*)p<=pBlock->m_pMemorySlots+m_CurrentBlockSize)
{
pBlock->recover_free_slot((memory_slot*)p);
return;
}
m_CurrentBlock++;
}
}
memory_slot* new_slot()
{
critical_section_lock lock(&m_CriticalSection);
memory_slot* pSlot=MemoryBlocks[m_CurrentBlock]->give_free_slot();
if(NULL==pSlot)
{
m_CurrentBlock=0;
while(NULL==pSlot)
{
memory_block* pCurrentBlock=MemoryBlocks[m_CurrentBlock];
if(pCurrentBlock)
pSlot=MemoryBlocks[m_CurrentBlock]->give_free_slot();
else
{
MemoryBlocks[m_CurrentBlock]=new memory_block(m_CurrentBlockSize);
m_CurrentBlockSize=(int)(1.1*(double)m_CurrentBlockSize);
pSlot=MemoryBlocks[m_CurrentBlock]->give_free_slot();
}
if(NULL==pSlot)
m_CurrentBlock++;
}
}
return pSlot;
}
};
class o_memory_slot
{
public:
LONG m_Last;
LONG m_Next;
#ifndef I_ALWAYS_USE_VIRTUAL_DESTRUCTORS_IN_POLYMORPHIC_BASE_CLASSES
void* m_pVoid;
#endif
o_memory_slot()
{
m_Last=0;
m_Next=1;
}
#ifndef I_ALWAYS_USE_VIRTUAL_DESTRUCTORS_IN_POLYMORPHIC_BASE_CLASSES
virtual void delete_object(void* pVoid)
{
}
#endif
};
class reference_controler_pool : public reference_controler_pool_base<o_memory_slot>
{
public:
template <class T>
reference_controler* new_reference_controler(T* pT);
};
#ifdef MONITOR_REF_CONTROLERS
static int stm_reference_controller_count;
#endif
#ifdef MONITOR_PTRS
static int stm_owner_ptr_count;
static int stm_ref_ptr_count;
static int stm_strong_ptr_count;
static int stm_deleter_count;
#endif
static reference_controler_pool stm_RefControlerPool;
LONG m_WeakCount;//Weak reference counter
LONG m_StrongCount;//Strong reference counter but if -tive represents lock count
void AddWeakRef()
{
if(m_WeakCount>0)
m_WeakCount++;
else
InterlockedDecrement(&m_WeakCount);
}
void AddStrongRef()
{
if(m_WeakCount>0)
{
m_StrongCount++;
}
else
InterlockedIncrement(&m_StrongCount);
}
void Lock()//Only lock weak reference - if it is already strong then no lock is added
{
if(m_WeakCount>0)//m_StrongCount<2)//if it is not already strong (+tive)
{
if(m_StrongCount>0)
m_StrongCount=0;
m_StrongCount--;//increase lock count (-tive)
}
else
InterlockedIncrement(&m_StrongCount);//++;
}
public:
#ifndef I_ALWAYS_USE_VIRTUAL_DESTRUCTORS_IN_POLYMORPHIC_BASE_CLASSES
virtual void delete_object()=0;
#endif
reference_controler()
: m_WeakCount(1), m_StrongCount(1)
{
#ifdef MONITOR_REF_CONTROLERS
reference_controler::stm_reference_controller_count++;
#endif
}
~reference_controler()
{
//Only deleted when it has nothing more to do
#ifdef MONITOR_REF_CONTROLERS
reference_controler::stm_reference_controller_count--;
#endif
}
bool ReleaseWeak()
{
if(m_WeakCount>0)
--m_WeakCount;
else
++m_WeakCount;
if(0==m_WeakCount && 0==m_StrongCount)
{
stm_RefControlerPool.delete_reference_controler(this);
return true;
}
else
return false;
}
bool ReleaseStrong()
{
if(0==--m_StrongCount)
{
return true;
}
else
return false;
}
bool DeleteIfZeroCounts()
{
if(0==m_WeakCount && 0==m_StrongCount)
{
stm_RefControlerPool.delete_reference_controler(this);
return true;
}
return false;
}
void Unlock()
{
if(m_StrongCount<0)//if it is a lock (+tive)
{
if(0==++m_StrongCount && 0==m_WeakCount)
stm_RefControlerPool.delete_reference_controler(this);
if(0==m_StrongCount)
m_StrongCount=1;
//delete this;
}
else if(ReleaseStrong())
throw xonor_ptr_fatal_exception(_T("Object deleted while used by Fast Pointer"));
//If strong count is +tive then no lock is needed
}
};
template <class T>
class reference_controler_impl : public reference_controler
{
#ifndef I_ALWAYS_USE_VIRTUAL_DESTRUCTORS_IN_POLYMORPHIC_BASE_CLASSES
T* m_pT;
#endif
public:
reference_controler_impl(T* pT)
{
#ifndef I_ALWAYS_USE_VIRTUAL_DESTRUCTORS_IN_POLYMORPHIC_BASE_CLASSES
m_pT=pT;
#endif
}
#ifndef I_ALWAYS_USE_VIRTUAL_DESTRUCTORS_IN_POLYMORPHIC_BASE_CLASSES
virtual void delete_object()
{
delete m_pT;
m_StrongCount=0;
}
#endif
};
};//namespace PRIVATE
using namespace PRIVATE;
//*************************************************************************************************
//Hidden classes used internally by pointer system but not visible in application code
//************************************************************************************************
template <class T> class smart_pointer_base //Base class for Auto, Weak and Fast pointers
{
protected:
//Friends
template<class U, class T2> friend ref_ptr<T2> up_cast(ref_ptr<U>const& r);
template<class U, class T2> friend ref_ptr<T2> up_cast(owner_ptr_base<U>& apT);
template<class U, class T2> friend ref_ptr<T2> up_cast(ref_pointer_base<U>const& r);
friend class ref_ptr<T>;
template<class U> friend class ref_ptr;
friend class fast_ptr<T>;
template<class U> friend class fast_ptr;
friend class ref_pointer_base<T>;
template<class U> friend class ref_pointer_base;
mutable reference_controler* m_pReferenceControler;
mutable T* m_pT;
smart_pointer_base() {m_pReferenceControler=NULL; m_pT=NULL;}
T* get_pointer_abs() const {return m_pT;}
void set_null() const
{
if(m_pReferenceControler)
m_pReferenceControler->ReleaseWeak();
m_pReferenceControler=NULL;
m_pT=NULL;
}
inline bool IsValidRef() const
{
if(m_pReferenceControler!= NULL && m_pReferenceControler->m_StrongCount!=0)
return true;
else
set_null();
return false;
}
public:
T* get_pointer()const {if(IsValidRef()) return m_pT; set_null(); return NULL;}
private:
//*****Methods to prevent operations which undermine the pointer system***
void* operator new(size_t s) {BAD_CODE; "Never dynamically create a smart pointer" }
operator void*() const {BAD_CODE "Never delete a smart pointer" }
operator smart_pointer_base<T>*()const {BAD_CODE "Do not use pointers to smart pointers"}
};
template <class T> class ref_pointer_base : public smart_pointer_base<T>
{
//Friends
friend class ref_ptr<T>;
template <class U> friend class ref_ptr;
friend class fast_ptr<T>;
template <class U> friend class fast_ptr;
friend class strong_ptr<T>;
template <class U> friend class strong_ptr;
protected:
//Key operations
ref_pointer_base() {}
public:
T* get_pointer()const {if(IsValidRef()) return m_pT; set_null(); return NULL;}
//Equality test with all types
bool operator==(smart_pointer_base<T>& wpT)const {return get_pointer()==wpT.get_pointer();}
template<class U> bool operator==(smart_pointer_base<U>const& wpT)const {return get_pointer()==static_cast<T*>(wpT.get_pointer());}
bool operator==(T*const pT)const {return get_pointer()==pT;}
//Inequality test with all types
bool operator!=(smart_pointer_base<T>const& wpT)const {return get_pointer()!=wpT.get_pointer();}
template<class U> bool operator!=(smart_pointer_base<U>const& wpT)const {return get_pointer()!=static_cast<T*>(wpT.get_pointer());}
private:
inline const T** operator&()
{
BAD_CODE ;//This would allow pointer value to be changed
}
};
template <class T> class scoped_value : public smart_pointer_base<T>
{
//Friends
friend class ref_ptr<T>;
template<class U> friend class ref_ptr;
friend class ref_pointer_base<T>;
template<class U> friend class ref_pointer_base;
//Key operations
reference_controler* AssureReferenceControler() const
{
//called when a reference is first taken from the owner
if(NULL==m_pReferenceControler)
{
const_cast< reference_controler*>( m_pReferenceControler)=reference_controler::stm_RefControlerPool.new_reference_controler<T>(m_pT);
}
return m_pReferenceControler;
}
void reset()
{
if(m_pReferenceControler!=NULL)
{
//Test for fast_ptr locking this object (-tive strong count)
if(m_pReferenceControler->m_StrongCount<0)
throw xonor_ptr_fatal_exception(_T("Trying to delete while used by Fast Pointer"));
m_pReferenceControler->m_StrongCount=0;
if(m_pReferenceControler->DeleteIfZeroCounts())
m_pReferenceControler=NULL;
if(m_pReferenceControler!=NULL)
m_pReferenceControler->ReleaseWeak();
}
}
public:
scoped_value() { }
~scoped_value() {reset();}
scoped_value(T* pT) { m_pT=pT; m_pReferenceControler=NULL; }
scoped_value* operator =(T* pT) { m_pT=pT; m_pReferenceControler=NULL; return this; }
BOOL operator!() { return (m_pT == NULL) ? TRUE : FALSE ; }
operator BOOL() const { return (m_pT != NULL) ? TRUE : FALSE ;}
T* get_pointer() const {return m_pT ;}
void OnPreDelete(T* pT) {/*Derived classes can implement action to take before deletion*/}
};
template <class T> class owner_ptr_base : public smart_pointer_base<T>
{
//Friends
friend class ref_ptr<T>;
template <class U> friend class ref_ptr;
friend class fast_ptr<T>;
template <class U> friend class fast_ptr;
friend class new_ptr<T>;
template <class U, class T2> friend ref_ptr<T2> up_cast(owner_ptr_base<U>& apT);
protected:
//Key operations
template <class U> void InnerCopy(owner_ptr_base<U>const& apT)
{
//Makes a copy of another owner_ptr
//Will not complile if T does not have default constructor
//and copy constructor
if(apT.m_pT!=NULL)
{
m_pT=new T;//Create a new object
*m_pT=*(apT.m_pT);//Copy members to new object
}
}
void OnPreDelete(T* pT)
{
//Derived classes can implement action to take before deletion
}
inline void ThrowIfNull() const
{
//Defined response to trying to derefence Null pointer
if(NULL==m_pT)
throw xonor_ptr_exception(_T("NULL owner_ptr"));
}
template <class U> reference_controler* AssureReferenceControler(U* pU) const
{
//called when a reference is first taken from the owner
if(NULL==m_pReferenceControler)
{
const_cast< reference_controler*>( m_pReferenceControler)=reference_controler::stm_RefControlerPool.new_reference_controler<U>(pU);
}
return m_pReferenceControler;
}
public:
T* get_pointer() const {return m_pT ; }
void reset()
{
if(m_pT!=NULL)
{
if(m_pReferenceControler!=NULL)
{
//Test for fast_ptr locking this object (-tive strong count)
if(m_pReferenceControler->m_StrongCount<0)
throw xonor_ptr_fatal_exception(_T("Trying to delete while used by Fast Pointer"));
if(m_pReferenceControler->ReleaseStrong())
{
OnPreDelete(m_pT);
#ifndef I_ALWAYS_USE_VIRTUAL_DESTRUCTORS_IN_POLYMORPHIC_BASE_CLASSES
m_pReferenceControler->delete_object();
#else
delete m_pT;
#endif
}
if(m_pReferenceControler->DeleteIfZeroCounts())
m_pReferenceControler=NULL;
if(m_pReferenceControler!=NULL)
m_pReferenceControler->ReleaseWeak();
}
else
{
OnPreDelete(m_pT);
delete m_pT;
}
m_pT=NULL;
m_pReferenceControler=NULL;
}
if(m_pReferenceControler!=NULL)
{
m_pReferenceControler->ReleaseWeak();//Release PtrHolder
m_pReferenceControler=NULL;//and forget it
}
}
};
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Software Author with engineering, science and mathematical background.
Many years using C++ to develop responsive visualisations of fine grained dynamic information largely in the fields of public transport and supply logistics. Currently interested in what can be done to make the use of C++ cleaner, safer, and more comfortable.