Introduction
A reference-based object must be managed with consideration to memory allocation and de-allocation. A garbage collector and smart-pointer helps us avoid these annoying considerations.
But, a standard C++ compiler has no garbage collector. And, in spite of some libraries implementing a smart-pointer, a C++ compiler has no reference count for an object, so the compiler can't manage the object's scope within functions.
The CRefObject
is not just a smart pointer, it supports and manages reference information of objects. So you can pass CRefObject
to a function and return from that function. In any scope, if you keep the CRefObject
instance, its object is never destroyed.
Also, when you want to store different types of objects in one container like ClassA
and ClassB
, what can you do? Using CSessionObject
you can do this without any additional work. Just reference the container with an Object-Key and you can store and retrieve these objects from the container.
Background
CRefObject
uses a technique implemented in CString
. CRefObject
allocates a memory block for an object as an unknown memory block followed by CObjectData
. CObjectData
has information for managing the reference counter.
This method has many advantages - it prevents defragmenting memory by CObjectData
.
class _TAllocator : public T {
public:
void* PASCAL operator new(size_t nSize) {
LPVOID pNewObj = new BYTE[nSize + sizeof(CObjectData)] ;
return ((BYTE*)pNewObj) + sizeof(CObjectData) ;
}
void PASCAL operator delete(void* p) {
delete [] (((CObjectData*)p) -1) ;
}
} ;
If you wish to know more about the principle behind CRefObject
, look at the CString
source code.
CSessionObject
started from the question 'How can I store all of CRefObject
objects in one std::map
class?'. Because STL is based on templates, if I want to use these I must define an explicit parameterized Type. However, CRefObject
is also template based, so I can't do it.
I thought about it, and had an idea!
CRefObject
doesn't manage a real object. It just manages unknown memory blocks. So, I decided to store these memory blocks in std::map
.
CSessionObject
represents an explicit Session object using CRefObject
. You can modify CRefObject
, but I didn't want to do that. So, I wrote another class. CManagedObjData
is a bridge to manage the reference count within CObjectData
and CSessionObject
. CSession
is the container which stores and retrieves Objects by the Key.
The download project also has a C++ Unit Test. I wrote some unit test routines based on CPPUnit Lite. The DLL must have a Test Entry Point.
extern "C" {
__declspec(dllexport) void TestEntryPoint()
{
TestResult tr;
TestRegistry::runAllTests(tr);
}
}
TestLoader.EXE loads the DLL and executes its Test Entry Point. You can find TestLoader.EXE in my Zip files, not in the CPPUnit Lite. TestLoader.EXE is written by me.
TestLoader.EXE xXx.DLL
If you use Visual Studio, use like this:
This is my setting, you must adapt it for your environment.
Using the code
First, you need to define a parameterized class.
typedef CRefObject<_TWorkspaceValue> CWorkspaceValue ;
CRefObject
has no constructor for base Type
. So, if you define it like this, no object will be created.
CWorkspaceValue WorkspaceValue ;
If you want to create a new instance for the object, you must define it like this:
CWorkspaceValue WorkspaceValue(NULL) ;
Finally, you can use this object just like a value object. No need to worry about memory management.
Do you want to assign this to a new one? Look at this:
CWorkspaceValue AnotherValue(WorkspaceValue) ;
CWorkspaceValue Others ;
Others = WorkspaceValue ;
AnotherValue
, Others
and WorkspaceValue
share one object - WorkspaceValue
. If you change an object's value from any one of them, it affects all of them.
To prevent this, you'd better use Lock
.
Others.Lock() ;
Others->Value = NewValue ;
Others.Unlock() ;
Lock()
method creates a new object. It works like a CString::Lock()
.
You can create a new instance from base type.
_TWorkspaceValue BaseType ;
BaseType.Value = NewValue ;
CWorkspaceValue v1(&BaseType) ;
Others = &BaseType ;
In function parameter and return value, you can use this like valued-object, but it works as a ref-object. No value copy, just counts a reference counter.
CWorkspaceValue GetWorkspace(LPCSTR szWorkspaceName)
{
return m_WsList[szWorkspaceName] ;
}
void InsertItem(CWorkspaceValue NewValue)
{
m_WsList[NewValue->WorkspaceName] = NewValue ;
}
If you want to reference base type, use the ->
operator.
For more information about CSessionObject
, you'd better reference RefObject.cpp in the Zip file.
Just what I say is, CSessionObject
is compatible with CRefObject
:).
History
- 06/10/2005 - Fixed 'SessionObject.h'. It reports a compile error when compiled with another project that uses 'SessionObject.h'.