65.9K
CodeProject 正在变化。 阅读更多。
Home

LipingPtr C++ 模板类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.04/5 (12投票s)

2008 年 6 月 29 日

CPOL

4分钟阅读

viewsIcon

30894

downloadIcon

344

C++ 智能指针模板类实现。

引言

LipingPtr 是一个引用计数的 C++ 智能指针模板类。它跟踪指针的使用情况,并在引用计数达到 0 时删除它。LipingPtr 试图将智能指针最常用的功能结合起来,并将它们表示在单个文件中。保持简单的用法也是 LipingPtr 的目标之一。它可能不包含智能指针可能拥有的所有功能;但它努力避免使用令人困惑的术语。

1.1 设计原则

高性能和易用性是 LipingPtr 的主要设计考虑因素。

1.2 线程安全

LipingPtr 在 Win32 和 Win64 中使用“临界区”来保护共享数据。在 Linux 中,它使用 pthread_mutex_t 进行保护。

1.3 支持自定义析构器

默认情况下,LipingPtr 使用 delete 来释放分配的内存。用户也可以定义自己的析构器来释放资源。

1.4 LipingArray

LipingArray 是一个派生自 LipingPtr 的类。它用于管理多维数组。它还可以将数组内容保存到文件或从文件中加载。LipingArray 在结束时发出 delete [] 来释放分配的内存。

1.5 BinData

BinData 是一个预定义的数据类型,它使用 LipingArray 来管理二进制数据。

1.6 FilePtr

它是一个预定义的数据类型,它使用 LipingPtr 来跟踪 FILE 指针。它也用于 LipingArray SaveFile() LoadFile()。当 FilePtr 超出作用域时,FilePtr 会关闭打开的文件。

2. 构建 LipingPtrTest 演示项目

2.1 Visual Studio 2005 构建

LipingPtrTest.sln 是 Visual Studio 2005 的解决方案文件。您可以选择 Win32 或 Win64 平台的构建。

2.2 Linux 构建

您可以使用 makefile 在 Linux 上构建 LipingPtrTest

3. 基本用法

3.1 管理对象指针

创建一个新的类实例,并使用 LipingPtr 来管理它。

示例代码

{
    LipingPtr<LipingPtrTest> p1(new LipingPtrTest);
    p1->Hello(true);
}

LipingPtrTest 实例 p1 将在代码块结束后被释放。

注意:LipingPtrTest 定义附在本文件末尾。

3.2 管理对象数组指针

3.2.1 使用 LipingArray 管理 LipingPtrTest 数组

这是创建 LipingPtrTest 数组并为每个数组元素调用 Hello 方法的示例代码。

{
    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 使用 LipingArray 管理 char 数组

{
    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 使用 BinData 管理 unsigned char 数组

此示例显示了如何使用 BinData 管理 unsigned char 数组以及如何将数据保存/加载到/从文件中。

{
    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 显式使用析构器

此示例代码显示了如何定义和使用析构器 (CppFree) 来释放由 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 将 LipingPtr 与 STL Vector 一起使用

此示例创建 LipingPtr 对象并将其放入 STL vector。LipingPtr 管理的内存将在 vector (tvector) 超出作用域时被释放。

{
    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 将 LipingPtr 与 STL Map 一起使用

a. 通过字符串 ID 添加 map 元素
{
    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. 添加 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. 将 LipingPtr 对象作为第一个 Map 元素

托管对象 (LipingPtrTest) 必须支持“<”运算符,才能将 LipingPtr 实例放入 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. 将 LipingPtr 与 STL Vector 和 Sort 算法一起使用

此示例代码将 LipingPtr 对象放入 STL vector 并使用 STL sort 方法对它们进行排序。

{
    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 和 ReleaseData 函数

LipingPtr LipingArray 提供了 AttachDetachReleaseData 函数来直接访问隐藏的原始指针。这些操作将影响所有引用同一原始指针的 LipingPtr LipingArray 对象。如果可以使用其他函数完成任务,则不建议频繁使用这些函数。

以下是一个示例代码,展示了 Attach Detach 的正确用法

{
    int arraySize = 100;
    int *a = new int[arraySize]; // allocate a new array
    LipingArray<int> ia(a, arraySize); // initialize ia with allocated array
    for (unsigned int i = 0; i < ia.Size(); i++) // assign values for each element
    {
        ia[i] = i;
    }

    {
        int *b = ia.Detach(); // detach the array from ia
        LipingArray<int> ib(b, arraySize); // let ib manage the array pointer
        for (int i = 0; i< arraySize; i++) // change the array element values
        {
            ib[i] = i*3;
        }
        ia.Attach(ib.Detach(), arraySize);
        // detach the array from ib and let ia manage the pointer
        LipingArray<int> aa(new int[arraySize], arraySize); // create a new array
        for (int i = 0; i< arraySize; i++) // assign value to aa elements
        {
            aa[i] = i;
        }

        LipingArray<int> ic = ia;
        ia.Attach(aa.Detach(), arraySize);
        // let ia manage aa's array pointer.
        // the old array pointer that ia manages will be released
        // before attach aa's pointer.
    }
}

此代码部分显示了复杂的 AttachDetachInitDataSaveFileLoadFile 函数用法

{
    LipingArray<long> xx;
    {
        unsigned int arraySize = 100;
        // Allocate the memory by arraySize
        LipingArray<long> a(arraySize);
        // Get the array arraySize by Size
        for (unsigned int i = 0; i < a.Size(); i++)
        {
            // Access the element by [] operator
            a[i] = 'a' + i%('z'-'a'+1);
        }

        // Direct access the buffer
        memset(a.RawPtr(), 0, a.Size()*sizeof(long));
        long *lx = new long[arraySize];
        // Attach a pre-allocated memory - the old memory is released
        a.Attach(lx, arraySize);
        // Attach a newly allocated array - the old memory is released
        a.Attach(new long[arraySize], arraySize);
        LipingArray<long> aa;
        aa = a;
        LipingArray<long> bb(aa);
        // Detach the allocated memory *** Careful to use!!! Advanced usage!!!
        lx = a.Detach();
        // Release the detached memory
        delete [] lx;
        LipingArray<long> cc(arraySize);
        // Get the array arraySize by Size
        for (unsigned int i = 0; i < cc.Size(); i++)
        {
            // Access the element by [] operator
            cc[i] = 'a' + i%('z'-'a'+1);
        }
        // Add another reference; the memory will be kept even cc is released
        xx = cc;
    }

    // Release the old memory got from cc; and track a new array
    xx = LipingArray<long>(10);
    // Do nothing
    xx = xx;
    XPoint point0;
    point0.x = 12;
    point0.y = 88;
    LipingArray<XPoint> xs(10);
    // set all points by point0 value
    xs.InitData(point0);
    // Save the content in a file
    xs.SaveFile("arrayDump.bin");
    xs.InitData(point0);
    // Load a file in buffer
    xs.LoadFile("arrayDump.bin");
    xs.ReleaseData();
    xs = LipingArray<XPoint>(5);
    // Load a file with a new buffer. The Size() is 10 after load
    xs.LoadFile("arrayDump.bin");
}

3.4 多维数组用法

LipingArray 支持多维数组。示例如下,并附有注释

// Two dimensional array:
{
    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"); // Save the content in a file
    LipingArray<Point, 2> xl(10, 8);
    xl.LoadFile("arrayDump_xa.bin"); // Load the content from file
    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");
}

// Three dimensional array:
{
    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");
    // The array content will be released when leaving the section.
}

// Array assignment:
{
    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;
    //xa1 = xb; // Compile time error. - it is by design
    // to avoid confusion at compile time.
    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 支持的运算符

LipingPtr 支持以下运算符

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; 

以下是使用支持的运算符的示例代码

{
    // Different constructors:
    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");
    }
}

// more about operator “=” :
{
    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. 使用 LipingPtr 管理其他指针示例

这是一个示例,展示了如何使用 LipingPtr 来管理 Intel OpenCV 图像指针。

4.1 为 OpenCV IplImage 定义析构器

struct CvReleaseIplImage
{
    static void Free(IplImage *p)
    {
        if (p) cvReleaseImage(&p);
    }
};
typedef LipingPtr<IplImage, CvReleaseIplImage> CvImagePtr;

4.2 使用定义的类型返回 CvImagePtr 指针

返回的图像将在无人引用时自动释放。

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. 演示类定义

5.1 示例代码中使用的数据结构

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 文件内容

#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;
}

历史

  • 2008 年 6 月 29 日:初次发布
© . All rights reserved.