Introduction
LipingPtr
is a reference counted C++ Smart Pointer Template Class. It keeps track of the pointer usage and deletes it when the reference counter reaches 0
. LipingPtr
tried to combine most frequently used features of smart pointers and represent them in a single file. Keeping the usage simple is another goal of LipingPtr
. It may not include all the functionalities smart pointers could have; but it tries hard to avoid using confusing terminologies.
1.1 Design Principle
High performance and easy to use are the major design considerations for LipingPtr
.
1.2 Thread-safe
LipingPtr
uses “Critical Section” in Win32 and Win64 for the shared data protection. It uses pthread_mutex_t
for the protection in Linux.
1.3 Support Custom De-Allocator
By default, LipingPtr
uses delete
to release the allocated memory. The user can also define his or her own de-allocator to release the resources.
1.4 LipingArray
LipingArray
is a class that derived from LipingPtr
. It is designed for managing multi dimensional arrays. It can also save and load array content to/from files. LipingArray
issues delete []
to release allocated memory at the end.
1.5 BinData
BinData
is a predefined data type which uses LipingArray
to manage binary data.
1.6 FilePtr
It is a predefined data type which uses LipingPtr
to keep track of FILE pointer. It is also used in LipingArray SaveFile()
and LoadFile()
. FilePtr
closes the opened file(s) when the FilePtr
goes out of scope.
2. Build LipingPtrTest Demo Project
2.1 Visual Studio 2005 Build
LipingPtrTest.sln is the solution file for Visual Studio 2005. You can select the build for Win32 or Win64 platforms.
2.2 Linux Build
You can use the makefile to build LipingPtrTest
on Linux.
3. Basic Usage
3.1 Manage Object Pointer
Create a new class instance and use LipingPtr
to manage it.
Sample Code
{
LipingPtr<LipingPtrTest> p1(new LipingPtrTest);
p1->Hello(true);
}
The LipingPtrTest
instance p1
will be released when it is out of the code section.
Note: LipingPtrTest
definition is attached at the end of this file.
3.2 Manage Object Array Pointer
3.2.1 Manage LipingPtrTest array by using LipingArray
This is the sample code that creates an array of LipingPtrTest
and calls the Hello
method for each array element.
{
int arraySize = 3;
LipingArray<LipingPtrTest> cp(new LipingPtrTest[arraySize]);
for (int i = 0; i < arraySize; i++)
{
if (printit) cp.RawPtr()[i].Hello(printit);
}
}
3.2.2 Manage char array by using LipingArray
{
const int arraySize = 1024*10;
LipingArray<char> cp(new char[arraySize]);
strcpy_s(cp.RawPtr(), arraySize, "Hello LipingArray");
if (printit) printf("LipingPtr<char> = %s\n", cp.RawPtr());
}
3.2.3 Manage unsigned char array by BinData
This sample shows how to use BinData
to manage the unsigned char
array and Save/Load data to/from files.
{
const int arraySize = 256;
BinData bin(arraySize);
unsigned char* p = bin.RawPtr();
for (int i = 0; i < arraySize; i++)
{
p[i] = (unsigned char) i%255;
}
bin.SaveFile("binData.bin");
bin.ReleaseData();
BinData tbin;
tbin.LoadFile("binData.bin");
}
3.2.4 Explicitly Use De-Allocator
This sample code shows how to define and use a de-allocator (CppFree
) to release the memory allocated by malloc.
template<class T>
class CppFree
{
public:
static void Free(T *p)
{
LIPING_PTR_DEBUG_TRACE(p);
if (p) free((void*)p);
}
};
{
const int arraySize = 1024*10;
LipingPtr<char, CppFree<char> >
cp((char*)malloc(sizeof(char)*arraySize));
strcpy(cp.RawPtr(), "Hello LipingArray");
PrintCp(cp.RawPtr(), printit);
}
3.2.5 Use LipingPtr with STL Vector
This sample creates LipingPtr
object and puts it in STL vector. The LipingPtr
managed memory will be released when the vector (tvector
) goes out of scope.
{
LipingPtr<LipingPtrTest> p1(new LipingPtrTest);
std::vector< LipingPtr<LipingPtrTest> > tvecotr;
for(int i=0; i<3; i++)
{
tvecotr.push_back(
LipingPtr<LipingPtrTest>(new LipingPtrTest()) );
}
for(unsigned int i=0; i<tvecotr.size(); i++)
{
tvecotr[i]->Hello(printit);
}
}
3.2.6 Use LipingPtr with STL Map
a. Add map element by string ID
{
typedef LipingPtr<LipingPtrTest> TestPtr;
map< string, TestPtr > smap;
smap["hello-1"] = TestPtr(new LipingPtrTest());
smap["hello-2"] = TestPtr(new LipingPtrTest());
smap["hello-3"] = TestPtr(new LipingPtrTest());
map< string, TestPtr >::iterator it;
for(it = smap.begin(); it != smap.end(); it++)
{
if (printit) printf("Index string = %s; ",
(*it).first.c_str());
(*it).second->Hello(printit);
}
}
b. Different Ways to Add Items in Map
if (printit) printf("Different ways for adding map items:\n");
{
map< int, TestPtr > imap;
if (printit) printf(" << Two step add:\n");
TestPtr inputPtr = new LipingPtrTest();
imap[111] = inputPtr;
if (printit) printf(" >> End two step add\n");
if (printit) printf("One step add:\n");
imap[121] = TestPtr(new LipingPtrTest());
if (printit) printf("end - One step add\n");
if (printit) printf("Two step add by pair:\n");
PtrPair x(131, new LipingPtrTest());
imap.insert(x);
if (printit) printf("end - Two step add by pair\n");
if (printit) printf("One step add by pair:\n");
imap.insert(PtrPair(141, new LipingPtrTest()));
if (printit) printf("end - One step add by pair\n");
}
c. Put LipingPtr Object as First Map Element
The managed object (LipingPtrTest
) must supports “<
” operator in order to put the LipingPtr
instance in STL map.
{
typedef LipingPtr<LipingPtrTest> TestPtr;
typedef pair<TestPtr, int> SiPair;
map< TestPtr, int > imap;
imap.insert(SiPair(new LipingPtrTest(), 141));
imap.insert(SiPair(new LipingPtrTest(), 142));
imap.insert(SiPair(new LipingPtrTest(), 143));
map< TestPtr, int >::iterator it;
for(it = imap.begin(); it != imap.end(); it++)
{
if (printit) printf("Int value = %d; ", (*it).second);
(*it).first->Hello(printit);
}
}
d. Use LipingPtr with STL Vector and Sort Algorism
This sample code puts LipingPtr
objects into STL vector and sorts them by STL sort method.
{
const int arraySize = 10;
typedef LipingPtr<LipingPtrTest> LipingTestPtr;
typedef vector<LipingTestPtr> VTest;
VTest ta;
if (printit) printf("\n");
if (printit) printf("Print random items:\n");
for (unsigned int i = 0; i < arraySize; i++)
{
LipingTestPtr ptr(new LipingPtrTest);
ptr->index = (int)(rand());
ptr->Hello(printit);
ta.push_back(ptr);
}
std::sort(ta.begin(), ta.end());
VTest::iterator it;
if (printit) printf("\n");
if (printit) printf("Print sorted items:\n");
for (it = ta.begin(); it != ta.end(); it++)
{
(*it)->Hello(printit);
}
if (printit) printf("\n");
}
3.3 Attach, Detach, and ReleaseData Functions
LipingPtr
and LipingArray
provide Attach
, Detach
, and ReleaseData
functions to directly access the hidden raw pointer. These actions will affect all LipingPtr
or LipingArray
objects that are referring to the same raw pointer. It is not recommended to use these functions often if you can use other functions to complete the task.
Here is a sample code that shows the proper usage for Attach
and Detach
:
{
int arraySize = 100;
int *a = new int[arraySize]; LipingArray<int> ia(a, arraySize); for (unsigned int i = 0; i < ia.Size(); i++) {
ia[i] = i;
}
{
int *b = ia.Detach(); LipingArray<int> ib(b, arraySize); for (int i = 0; i< arraySize; i++) {
ib[i] = i*3;
}
ia.Attach(ib.Detach(), arraySize);
LipingArray<int> aa(new int[arraySize], arraySize); for (int i = 0; i< arraySize; i++) {
aa[i] = i;
}
LipingArray<int> ic = ia;
ia.Attach(aa.Detach(), arraySize);
}
}
This code section shows the complex Attach
, Detach
, InitData
, SaveFile
, and LoadFile
functions usage:
{
LipingArray<long> xx;
{
unsigned int arraySize = 100;
LipingArray<long> a(arraySize);
for (unsigned int i = 0; i < a.Size(); i++)
{
a[i] = 'a' + i%('z'-'a'+1);
}
memset(a.RawPtr(), 0, a.Size()*sizeof(long));
long *lx = new long[arraySize];
a.Attach(lx, arraySize);
a.Attach(new long[arraySize], arraySize);
LipingArray<long> aa;
aa = a;
LipingArray<long> bb(aa);
lx = a.Detach();
delete [] lx;
LipingArray<long> cc(arraySize);
for (unsigned int i = 0; i < cc.Size(); i++)
{
cc[i] = 'a' + i%('z'-'a'+1);
}
xx = cc;
}
xx = LipingArray<long>(10);
xx = xx;
XPoint point0;
point0.x = 12;
point0.y = 88;
LipingArray<XPoint> xs(10);
xs.InitData(point0);
xs.SaveFile("arrayDump.bin");
xs.InitData(point0);
xs.LoadFile("arrayDump.bin");
xs.ReleaseData();
xs = LipingArray<XPoint>(5);
xs.LoadFile("arrayDump.bin");
}
3.4 Multi Dimensional Array Usage
LipingArray
supports multi dimensional arrays. The sample code and comments are listed below:
{
unsigned int dx = 10, dy = 8;
LipingArray<Point, 2> xa(dx, dy);
for (unsigned int x = 0; x < dx; x++)
{
for (unsigned int y = 0; y < dy; y++)
{
Point *p = &xa.Element(x, y);
p->x = x;
p->y = y;
}
}
for (unsigned int x = 0; x < dx; x++)
{
if (printit) printf("\n");
for (unsigned int y = 0; y < dy; y++)
{
Point *p = &xa.Element(x, y);
if (printit) printf("%d,%d ", p->x, p->y);
}
}
if (printit) printf("\n");
for (unsigned int y = 0; y < dy; y++)
{
if (printit) printf("\n");
for (unsigned int x = 0; x < dx; x++)
{
Point *p = &xa.Element(x, y);
if (printit) printf("%d,%d ", p->x, p->y);
}
}
if (printit) printf("\n");
xa.SaveFile("arrayDump_xa.bin"); LipingArray<Point, 2> xl(10, 8);
xl.LoadFile("arrayDump_xa.bin"); if (printit) printf("\n");
if (printit) printf("Print loaded two dimensional array:");
for (unsigned int y = 0; y < dy; y++)
{
if (printit) printf("\n");
for (unsigned int x = 0; x < dx; x++)
{
Point *p = &xl.Element(x, y);
if (printit) printf("%d,%d ", p->x, p->y);
}
}
if (printit) printf("\n");
}
{
unsigned int dx = 5, dy = 3, dz = 8;
LipingArray<CpPoint, 3> xa(dx, dy, dz);
if (printit) printf("Dimensions <%d> Size: ", xa.Dimensions());
for (unsigned int i = 0; i < xa.Dimensions(); i++)
{
if (printit) printf("%d, ", xa.DimSize(i));
}
for (unsigned int x = 0; x < dx; x++)
{
for (unsigned int y = 0; y < dy; y++)
{
for (unsigned int z = 0; z < dz; z++)
{
CpPoint *p = &xa.Element(x, y, z);
p->x = x;
p->y = y;
p->z = z;
}
}
}
for (unsigned int x = 0; x < dx; x++)
{
if (printit) printf("\n");
for (unsigned int y = 0; y < dy; y++)
{
if (printit) printf("\n");
for (unsigned int z = 0; z < dz; z++)
{
CpPoint *p = &xa.Element(x, y, z);
if (printit) printf("%d,%d,%d ", p->x, p->y, p->z);
}
}
}
for (unsigned int z = 0; z < dz; z++)
{
if (printit) printf("\n");
for (unsigned int y = 0; y < dy; y++)
{
if (printit) printf("\n");
for (unsigned int x = 0; x < dx; x++)
{
CpPoint *p = &xa.Element(x, y, z);
if (printit) printf("%d,%d,%d ", p->x, p->y, p->z);
}
}
}
if (printit) printf("\n\n");
}
{
unsigned int dx = 3, dy = 5, dz = 10;
LipingArray<Point, 2> xa(dx, dy);
LipingArray<Point, 3> xb(dx, dy, dz);
LipingArray<Point, 2> xa1(dx, dy+1);
xa1 = xa;
if (printit) printf("Dimensions <%d> Size: ", xa.Dimensions());
for (unsigned int i = 0; i < xa.Dimensions(); i++)
{
if (printit) printf("%d, ", xa.DimSize(i));
}
}
3.5 Supported Operators
LipingPtr
supports the following operators:
LipingPtr& operator=(const LipingPtr& inputPtr);
LipingPtr& operator=(T* rawPointer);
T* operator->() const;
T& operator*() const;
bool operator!=(const void* p) const;
bool operator!() const;
bool operator==(const void* p) const;
bool operator!=(const LipingPtr &inputPtr) const;
bool operator==(const LipingPtr &inputPtr) const;
bool operator<(const LipingPtr &inputPtr) const;
Here is the sample code which uses the supported operators:
{
LipingPtr<LipingPtrTest> p1(new LipingPtrTest);
LipingPtr<LipingPtrTest> p2(p1);
LipingPtr<LipingPtrTest> p3 = p1;
LipingPtr<LipingPtrTest> p4(NULL);
CallHello(p4);
if (p4 != NULL)
{
p4->Hello(printit);
(*p4).Hello(printit);
}
if (p4 == NULL)
{
if (printit) printf(" Use == operator to check ===> p4 is NULL\n");
}
if (!p4)
{
if (printit) printf(" Use ! operator to check ===> p4 is NULL\n");
}
p4 = p1;
CallHello(p4);
if (p4 != NULL)
{
p4->Hello(printit);
(*p4).Hello(printit);
}
if (p4 == NULL)
{
if (printit) printf(" ===> p4 is NULL\n");
}
LipingPtr<LipingPtrTest> p5(new LipingPtrTest);
LipingPtr<LipingPtrTest> p6(new LipingPtrTest);
if (printit) printf("Call member by -> operator:\n");
p5->Hello(printit);
p6->Hello(printit);
if (printit) printf("Call member by * operator:\n");
(*p5).Hello(printit);
(*p6).Hello(printit);
p1 = p5;
LipingPtr<LipingPtrTest> p7(p1);
LipingPtr<LipingPtrTest> p8 = p1;
LipingPtr<LipingPtrTest> p9(p1);
if (p8 == p1)
{
if (printit) printf("p8 == p1\n");
}
if (p8 != p1)
{
if (printit) printf("p8 != p1\n");
}
p8 = p2;
if (p8 == p1)
{
if (printit) printf("p8 == p1\n");
}
if (p8 != p1)
{
if (printit) printf("p8 != p1\n");
}
}
{
LipingPtr<ChPoint> xa1 = new ChPoint(1,2);
ChPoint *p2 = new ChPoint(2,2);
xa1 = p2;
LipingPtr<ChPoint> xa2 = new ChPoint(3,1);
xa1 = xa2;
LipingPtr<ChPoint> xa3;
xa3 = xa1 = xa2 = new ChPoint(3,3);
}
4. Use LipingPtr Manage Other Pointers Sample
Here is a sample that shows how to use LipingPtr
to manage Intel OpenCV image pointer.
4.1 Define a De-Allocator for OpenCV IplImage
struct CvReleaseIplImage
{
static void Free(IplImage *p)
{
if (p) cvReleaseImage(&p);
}
};
typedef LipingPtr<IplImage, CvReleaseIplImage> CvImagePtr;
4.2 Use Defined Type to Return CvImagePtr Pointer
The returned image will be released automatically when no one references it.
CvImagePtr GetImageEdge(IplImage * sourceImage, float edgeThresh)
{
IplImage *distImage = cvCreateImage(
cvSize(sourceImage->width,sourceImage->height), IPL_DEPTH_8U, 1);
CvImagePtr distPtr(distImage);
cvCanny(sourceImage, distImage, (float)edgeThresh, (float)edgeThresh*3, 3);
cvNot( distImage, distImage );
return distPtr ;
}
5. Demo Class Definition
5.1 Data Structures Used in Sample Code
const int MaxNameLen = 50;
struct MyRec
{
char name[MaxNameLen];
int age;
};
struct Point { int x; int y; };
struct XPoint { int x; int y; };
struct CpPoint
{
char x;
char y;
char z;
};
struct ChPoint
{
char x;
char y;
ChPoint(char ix, char iy):x(ix), y(iy) {};
};
5.2 LipingPtrTest.h
LipingPtrTest.h file content:
#pragma once
#include "LipingPtr.h"
class LipingPtrTest
{
public:
bool printit;
int index;
static int counter;
public:
LipingPtrTest();
LipingPtrTest(bool printTrace);
~LipingPtrTest();
void Hello(bool printit);
bool operator<(const LipingPtrTest &xobj) const;
};
5.3 LipingPtrTest.cpp
#include "LipingPtrTest.h"
#include <string>
#include <vector>
#include <map>
int LipingPtrTest::counter = 0;
LipingPtrTest::LipingPtrTest() : index(0), printit(true)
{
LIPING_PTR_DEBUG_TRACE(this);
index = counter++;
#ifdef LIPING_PTR_OUTPUT_DEBUG_TRACE
if (printit) printf("Object:%p; index:%d\n", this, index);
#endif
}
LipingPtrTest::LipingPtrTest(bool printTrace) : index(0), printit(printTrace)
{
LIPING_PTR_DEBUG_TRACE(this);
index = counter++;
#ifdef LIPING_PTR_OUTPUT_DEBUG_TRACE
if (printit) printf("Object:%p; index:%d\n", this, index);
#endif
}
LipingPtrTest::~LipingPtrTest()
{
LIPING_PTR_DEBUG_TRACE(this);
}
void LipingPtrTest::Hello(bool printit)
{
LIPING_PTR_DEBUG_TRACE(this);
if (printit) printf("LipingPtrTest [%d] [%p]\n", index, this);
}
bool LipingPtrTest::operator<(const LipingPtrTest &xobj) const
{
bool retval = this->index < xobj.index;
return retval;
}
History
- 29th June, 2008: Initial post