Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Reference-based Object Set

0.00/5 (No votes)
8 Jun 2005 1  
CRefObject is not a smart pointer. It is a reference manager class for value-based objects.

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.

// Copy this and paste to your code

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'.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here