Teigha SDK Developer 智能指针 #2

文章目录

Kernel SDK Developer’s Guide

Basic Operations-Work with Smart Pointers

Creating a Standard Implementation of the Reference Counter

OdRxObjectImpl模板类用于创建类及其实例,当程序使用指向实例的智能指针进行操作时,这些类及其实例将计数引用。此模板创建基类的addRef()、numRefs()和release()虚方法的引用计数器和标准实现。当您在自动或静态内存中创建实例、为实例分配动态内存或从指定的类派生新类时,可以将此模板用作类的包装。
如果您想为静态或动态实例创建自己的类,请使用以下类定义从OdRxObject基类派生类:

class MyObj : public OdRxObject
{
 public:
   MyObj();
   ~MyObj();
};

您不需要将ODRX_HEAP_OPERATORS宏添加到类定义中,因为新操作符和删除操作符的标准实现是在OdRxObjectImpl类中定义的。与类定义一起,您应该使用OdSmartPtr模板声明类的智能指针类型:

typedef OdSmartPtr<MyObj> MyObjPtr;

要在自动或静态内存中创建实例,请在声明变量时使用OdRxObjectImpl模板作为类的包装:

OdRxObjectImpl<MyObj> my;

要在动态内存中创建实例,请在代码中声明类类型的智能指针,并使用createObject()方法和OdRxObjectImpl模板,而不使用(new)操作符:

MyObjPtr pSmart = OdRxObjectImpl<MyObj>::createObject();

createObject()方法是在OdRxObjectImpl模板中定义的伪构造函数。伪构造函数使用(new)操作符创建已定义类的实例,创建指向它的智能指针,正确初始化引用计数器,并返回指向实例的智能指针。伪构造函数有以下标准实现:

static OdSmartPtr<TInterface> createObject()
{
   return OdSmartPtr<TInterface>(static_cast<TInterface*>(new OdRxObjectImpl<T, TInterface>), kOdRxObjAttach);
}

伪构造函数使用OdSmartPtr模板创建智能指针,并使用kOdRxObjAttach选项在创建实例时抑制引用计数器的递增。这是必要的,因为默认情况下引用计数器设置为1,而第一次赋值将使其递增。
如果你想在所有的类中插入智能指针功能,从你自己的类中,直接从OdRxObjectImpl模板中派生类,并在类定义中重新定义伪构造函数:

class MyObj : public OdRxObjectImpl<OdRxObject>
{
 public:
   static OdSmartPtr<MyObj> createObject() 
   { 
      return OdSmartPtr<MyObj>(new MyObj, kOdRxObjAttach); 
   }
 public:
   MyObj();
   ~MyObj();
};

若要在自动或静态内存中创建实例,请在不使用模板的情况下声明类类型的变量:

MyObj my;

要在动态内存中创建一个实例,声明一个类类型的智能指针,使用伪构造函数而不使用模板和新操作:

MyObjPtr pSmart = MyObj::createObject();

你可以声明一个智能指针,并分配给它的静态实例地址:

MyObjPtr pSmart = &my;

您不需要使用delete操作符,因为智能指针控制内存并在它们的引用计数器变为0时销毁动态实例。当静态实例放弃程序作用域时,它们将被自动销毁。

Using the Standard Implementation of the Reference Counter

在引用计数示例中使用OdRxObjectImpl模板涉及到实现TestStaticInstance()和TestDynamicInstance()函数。
要使用智能指针,在定义它和使用OdSmartPtr模板定义智能指针类型时,必须从OdRxObject类派生类:

class MyObj : public OdRxObject
{
 public:
   MyObj();
   ~MyObj();
};

typedef OdSmartPtr<MyObj> MyObjPtr;

要为您自己的类的静态实例添加标准智能指针实现,您必须在代码中声明变量时使用OdRxObjectImpl模板。测试功能实现如下:

void TestStaticInstance()
{
   OdRxObjectImpl<MyObj> my;

   RefCountTest(&my);

   odPrintConsoleString(L"\\nReturn from RefCountTest()\\n  Reference counter: %d\\n", my.numRefs());
   getch();
}

要为自己的类的动态实例添加标准智能指针实现,您必须在代码中声明一个智能指针,并在不使用新操作的情况下使用OdRxObjectImpl模板和伪构造函数。测试功能实现如下:

void TestDynamicInstance()
{
   MyObjPtr pSmart0 = OdRxObjectImpl<MyObj>::createObject();

   RefCountTest(pSmart0.get());

   odPrintConsoleString(L"\\nReturn from RefCountTest()\\n  Reference counter: %d\\n", pSmart0->numRefs());
   getch();
}

要为所有派生自您自己的类的类插入智能指针功能,您必须通过OdRxObjectImpl模板从OdRxObject类派生类,并在派生类中重新定义伪构造函数:

class MyObj : public OdRxObjectImpl<OdRxObject>
{
 public:
   static OdSmartPtr<MyObj> createObject() 
   { 
     return OdSmartPtr<MyObj>(new MyObj, kOdRxObjAttach); 
   }
 public:
   MyObj();
   ~MyObj();
};

typedef OdSmartPtr<MyObj> MyObjPtr;

在声明变量时,不需要在代码中使用OdRxObjectImpl模板。静态实例的测试函数实现如下:

void TestStaticInstance()
{
   MyObj my;

   RefCountTest(&my);

   odPrintConsoleString(L"\\nReturn from RefCountTest()\\n  Reference counter: %d\\n", my.numRefs());
   getch();
}

动态实例需要伪构造函数,并将其命名为createObject。它必须创建已定义类的实例并返回指向它的智能指针。这个智能指针必须具有相同的类类型。createObject()方法在基类中定义,在派生类中不被访问。您必须定义自己的createObject()方法并在自己的类中表示它。伪构造函数必须禁止引用计数器的递增,因为在创建实例时,它的引用计数器默认设置为1。createObject()方法在使用OdSmartPtr模板创建智能指针时使用kOdRxObjAttach选项。动态实例的测试函数有以下实现:

void TestDynamicInstance()
{
   MyObjPtr pSmart0 = MyObj::createObject()

   RefCountTest(pSmart0.get());

   odPrintConsoleString(L"\\nReturn from RefCountTest()\\n  Reference counter: %d\\n", pSmart0->numRefs());
   getch();
}

如果没有在派生类中定义伪构造函数,则必须使用新操作符创建动态实例,并使用kOdRxObjAttach选项创建指向它的第一个智能指针,以抑制代码中引用计数器的递增。所有后续的智能指针都是在没有此选项的情况下正常创建的。最后一个智能指针销毁实例。测试功能实现如下:

void TestDynamicInstance()
{
   MyObj* pMyObj = new MyObj;
   
   MyObjPtr pSmart0(pMyObj, kOdRxObjAttach);
   
   RefCountTest(pSmart0.get());

   odPrintConsoleString(L"\\nReturn from RefCountTest()\\n  Reference counter: %d\\n", pSmart0->numRefs());
   getch();
}

MyObj类的构造函数和析构函数有以下实现:

MyObj::MyObj()
{
   odPrintConsoleString(L"\\nObject is created [counter: %d]\\n", numRefs());
}
MyObj::~MyObj()
{
   odPrintConsoleString(L"\\nObject is destroyed\\n");
}

静态实例和动态实例的引用计数结果相同:

Object is created [counter: 1]

1.(pMy)->(pSmart1)
  Reference counter: 2

2.(pSmart1)->(pSmart2),(pSmart3)
  Reference counter: 4

3.(pSmart2)=NULL
  Reference counter: 3

4.(pSmart3)->(pSmart4),(pSmart5)
  Reference counter: 5

5.(pSmart1)=NULL, (pSmart4)=NULL
  Reference counter: 3

6.(pSmart1)=NULL, (pSmart3)=NULL
  Reference counter: 2

Return from RefCountTest()
  Reference counter: 1

Object is destroyed

Return from Test

当测试函数创建MyObj类的实例时,实例的引用计数器将获得值1。当函数将实例的地址设置为第一个智能指针时,引用计数器将自己的值1+1=2递增。当函数创建第二个和第三个智能指针并将第一个智能指针的值赋给它们时,引用计数器将自己的值增加2个2+2=4。当函数将NULL赋给第二个智能指针时,引用计数器将自己的值减为4-1=3。当函数创建第四个和第五个智能指针并将第三个智能指针的值赋给它们时,引用计数器再次增加它自己的值3+2=5。当函数将NULL赋给第一个和第四个智能指针时,引用计数器将自己的值减2,5-2=3。当函数将NULL赋给第一个和第三个智能指针时,引用计数器将其自身的值减1 – 3 =2,因为第一个智能指针为NULL,并且不改变引用计数器。第五个智能指针存储实例的地址,但是函数没有为它赋值。当函数结束时,它会像自动对象一样销毁所有智能指针。销毁之前,智能指针的析构函数释放对指定对象的引用。因此,当第五个智能指针被销毁时,引用计数器自身的值将减1 -1。类似地,当TestStaticInstance()函数结束时,它会自动销毁静态实例。当TestDynamicInstance()函数结束时,它将销毁零智能指针,这将减少引用计数器1-1=0。结果,引用计数器变为零,最后这个智能指针自动销毁动态实例。不需要删除操作符;智能指针控制内存。

Example of Counting References

此示例演示引用计数器的空实现或标准实现创建的静态和动态实例的引用计数。该示例在以下实现中使用了控制台应用程序项目:

#include "conio.h"
#include "OdaCommon.h"
#include "OdToolKit.h"
#include "..\\..\\Kernel\\Extensions\\ExServices\\ExHostAppServices.h"
#include "..\\..\\Kernel\\Extensions\\ExServices\\ExSystemServices.h"

class MyApp : public ExSystemServices 
{
 protected:
   ODRX_USING_HEAP_OPERATORS(ExSystemServices);

 public:
   MyApp() {};
};

void TestStaticInstance();
void TestDynamicInstance();

int main()
{
   OdStaticRxObject<MyApp> svcs;

   odInitialize(&svcs);

   odPrintConsoleString(L"\\nCreating the static instance");
   TestStaticInstance();
   odPrintConsoleString(L"\\nReturn from Test");
   getch();

   odPrintConsoleString(L"\\n\\n");

   odPrintConsoleString(L"\\nCreating the dynamic instance");
   TestDynamicInstance();
   odPrintConsoleString(L"\\nReturn from Test");
   getch();

   odUninitialize();

   return 0;
}

该示例为静态创建的测试实例定义TestStaticInstance()函数,为动态创建的测试实例定义TestDynamicInstance()函数。两个函数调用RefCountTest()函数,该函数获取原始指针定义类的实例(MyObj)来源于OdRxObject,和两个功能创建新的智能指针,指定实例的地址(或零),并打印引用计数器后赋值操作符。函数的实现如下:

void RefCountTest(MyObj* pMy)
{
   MyObjPtr pSmart1 = pMy;
   odPrintConsoleString(L"\\n1.(pMy)->(pSmart1)\\n  Reference counter: %d\\n", pMy->numRefs());
   getch();

   MyObjPtr pSmart2 = pSmart1;
   MyObjPtr pSmart3 = pSmart2;
   odPrintConsoleString(L"\\n2.(pSmart1)->(pSmart2),(pSmart3)\\n  Reference counter: %d\\n", pMy->numRefs());
   getch();

   pSmart2 = NULL;
   odPrintConsoleString(L"\\n3.(pSmart2)=NULL\\n  Reference counter: %d\\n", pMy->numRefs());
   getch();

   MyObjPtr pSmart4 = pSmart3;
   MyObjPtr pSmart5 = pSmart4;
   odPrintConsoleString(L"\\n4.(pSmart3)->(pSmart4),(pSmart5)\\n  Reference counter: %d\\n", pMy->numRefs());
   getch();

   pSmart1 = NULL;
   pSmart4 = NULL;
   odPrintConsoleString(L"\\n5.(pSmart1)=NULL, (pSmart4)=NULL\\n  Reference counter: %d\\n", pMy->numRefs());
   getch();

   pSmart1 = NULL;
   pSmart3 = NULL;
   odPrintConsoleString(L"\\n6.(pSmart1)=NULL, (pSmart3)=NULL\\n  Reference counter: %d\\n", pMy->numRefs());
   getch();
}

TestStaticInstance()和TestDynamicInstance()函数的实现取决于用户定义类(MyObj)的定义,这个类可以从使用OdStaticRxObject类的空实现派生,也可以从使用OdRxObjectImpl类的标准实现派生。

Implementing Smart Pointers

OdSmartPtr模板类和OdRxObjectPtr类用于创建和声明派生自OdRxObject类的类的智能指针实例。智能指针存储实例的地址,修改实例的引用计数器,并执行内存控制。要控制实例,类必须实现numRefs()、addRef()和release()方法。您可以使用OdRxObjectImpl模板来创建标准实现,或者使用OdStaticRxObject模板来创建引用计数功能的空实现。
OdRxObjectPtr类是一个随时可用的非类型化智能指针,它可以控制从OdRxObject基类派生的任何类的实例。当它使用指针执行操作时,它不会验证所存储对象的类型。
OdSmartPtr类是创建为指定类指定类型的智能指针功能实现的模板。它在使用指针执行操作时检查类类型。必须使用(typedef)语句为类创建智能指针类型。例如,如果你有MyObj类以任何方式派生自OdRxObject基类,你应该使用以下定义来声明你的类的智能指针类型:

typedef OdSmartPtr<MyObj> MyObjPtr;

您定义的类型必须是: ClassNamePtr。类型名的后缀“Ptr”是必需的。
要创建智能指针的实例,请在变量前使用其类型名:

MyObjPtr pSmart;
OdRxObjectPtr pSmartRx;

你也可以在变量名之前的代码中使用OdSmartPtr模板:

OdSmartPtr<MyObj> pSmart;

当你使用伪构造函数在动态内存中创建一个实例时,它会返回一个智能指针,你应该把它保存在用户定义的变量中:

MyObjPtr pSmart = OdRxObjectImpl<MyObj>::createObject();

当你声明智能指针时,你可以分配静态实例的地址:

OdRxObjectImpl<MyObj> my1;
OdStaticRxObject<MyObj> my2;

MyObjPtr pSmart1 = &my1;
MyObjPtr pSmart2 = &my2;

OdRxObjectPtr pSmartRx1 = &my1;
OdRxObjectPtr pSmartRx2 = &my2;

在声明智能指针时,可以将原始指针赋值给动态实例:

MyObj* pMy = new OdStaticRxObject<MyObj>;
MyObjPtr pSmart = pMy
OdRxObjectPtr pSmartRx = pMy;

当你声明智能指针时,你可以使用另一个智能指针初始化它:

MyObjPtr pSmart0 = pSmart;
OdRxObjectPtr pSmartRx0 = pSmart;

你可以使用构造函数,并传递给它的地址的实例时,你声明的智能指针:

MyObjPtr pSmart(pMy, kOdRxObjAttach);
OdRxObjectPtr pSmartRx(pMy, kOdRxObjAttach);

kOdRxObjAttach选项抑制引用计数器的递增。
您可以将智能指针声明为结构或类的成员。例如:

struct MyStructure {
  long idem;
  MyObjPtr pMySmart;
  OdRxObjectPtr pMySmartRx;
};

初始化这个结构的一个实例:

struct MyStructure myStr;

myStr.idem = 1;
myStr.pMySmart = &my1;
myStr.pMySmartRx = &my2;

您可以声明智能指针数组,并将其作为普通指针数组使用。例如:

OdRxObjectImpl<MyObj> Obj1;
OdRxObjectImpl<MyObj> Obj2;
OdRxObjectImpl<MyObj> Obj3;
OdRxObjectImpl<MyObj> Obj4;

MyObjPtr arrPtr[4];

arrPtr[0] = &Obj1;
arrPtr[1] = &Obj2;
arrPtr[2] = &Obj3;
arrPtr[3] = &Obj4;

for(int i=0 ; i < 4 ; i++) 
  odPrintConsoleString(L"\\nAddress=%x  Refs=%d", arrPtr[i], arrPtr[i]>numRefs());
  
OdRxObjectPtr arrPtrRx[4];

for(int j=0 ; j < 4 ; j++)  arrPtrRx[j] = arrPtr[3 – j];

Reference:
https://www.opendesign.com

By Lindoudou
Yancheng Institute of Technology School of Economic & Management
Email:lindingdou@163.com

 
© 版权声明
THE END
喜欢就支持一下吧
点赞594 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容