[中文]Teigha SDK Developer\’s Guide:Basic Operations-Work with Smart Pointers #1

在这里插入图片描述

Kernel SDK Developer’s Guide

Basic Operations-Work with Smart Pointers

智能指针是一种抽象的数据类型,它模拟指针,为访问对象和在运行时管理内存提供额外的功能,例如,自动销毁未使用的对象、抛出异常、检查所有者或检查边界。

Concept of Smart Pointers

智能指针是一种抽象的数据类型,它模拟指针,为访问对象和在运行时管理内存提供额外的功能,例如,自动销毁未使用的对象、抛出异常、检查所有者或边界检查。这些附加的特性旨在减少程序中指针的误用所引起的问题,同时保持效率。智能指针通常跟踪对象,它们有助于在运行时进行内存管理。
使用智能指针有助于避免通常由误用原始指针引起的问题:

  • 内存泄漏——程序将一个对象存储在它自己的动态内存中,但是没有一个指针来存储这个对象的地址——对象存在,但是没有任何东西使用它。
  • 空指针——指针存储在程序中被销毁的对象的地址——指针指向一个不存在的对象。
  • 不正确的异常抛出-指针是NULL或引用另一种类型的对象,而程序抛出一个异常,有人试图取消对它的引用-异常操作一个不正确的指针。
  • 超出范围-指针超出可用内存的范围。

智能指针的思想包括将动态内存中创建的对象的生存期与引用该对象的指针之间的操作进行匹配。在创建对象时,也为它创建了智能指针。当智能指针将另一个对象的地址作为新值获取时,它将检查其他智能指针对受控对象的引用是否存在,并在没有引用该对象的情况下销毁该对象。当智能指针被删除,但其他智能指针引用它时,被控对象不被删除。如果被删除的智能指针是最后一个引用,则被控制对象也随之被删除。因此,开发人员只执行对象的分配,而智能指针在运行时控制对象,在不使用对象时删除对象。
智能指针通常只与继承自基类的类一起工作,基类提供对指针特性的支持。它们是类层次结构的典型,不能使用内部数据类型。
实现智能指针的另一个原因是它的自动引用计数技术。该技术将存储受控对象地址的智能指针的数量与存储在受控对象中的对它的引用的数量相匹配。被控对象本身必须将引用计数器存储为正整数值。当智能指针获得被控对象的地址时,该对象必须增加一个引用计数器。当一个智能指针被删除、设置为NULL或丢失被控制对象时,该对象必须减少一个引用计数器。如果智能指针在引用现有对象时获得对新对象的引用,则现有对象必须减少自己的引用计数器,而新对象必须增加自己的引用计数器。当引用计数器为零时,不使用被控对象,可以删除该对象。这个实现提供了可靠性、可用性、性能和易用性。

Overview of Classes that Implement Smart Pointers

该库支持用于访问数据库对象和在运行时管理内存的智能指针技术。要使用智能指针,请使用以下类和模板:

 OdRxObject abstract class
OdRxObjectImpl template
OdStaticRxObject template
OdRxObjectPtr class
OdSmartPtr template class
OdBaseObjectPtr class

OdRxObject class

OdRxObject abstract类为所有类提供基本接口,仅用于派生新类。您不能创建此类的实例。它声明了三种处理智能指针的方法:

 numRefs() virtual method —返回引用计数器的值。
 addRef() pure virtual method —递增引用计数器。
 release() pure virtual  method — 递减引用计数器。

这些方法没有实现,它们是处理智能指针的基本接口的声明。派生自OdRxObject类的类必须重新定义这些方法来修改引用计数器。智能指针将调用重新定义的方法来计数类实例的引用数量。您可以在指定的类中实现这些方法,也可以使用OdRxObjectImpl和OdStaticRxObject模板来创建这些方法的标准实现。

OdRxObjectImpl template

OdRxObjectImpl模板为派生自OdRxObject类的类创建numRefs()、addRef()和release()方法的标准实现。这个模板将指定的类使用一个新类继承指定类的所有方法,定义了新的、删除、和赋值操作符,声明引用计数器为核心的结构,实现了numRefs()方法,它返回引用计数器的值,实现了addRef()引用计数器递增方法,实现了release()方法将引用计数器,检查是否引用计数器具有积极价值,并在引用计数器为零时调用delete操作符。重载的delete操作符一起销毁指定类和包装类的对象。该模板声明的引用计数器是一个OdRefCounter结构,它通过互锁实现计数操作,并在线程之间和进程之间执行同步。OdRxObjectImpl模板还定义了指定类的伪构造函数,该构造函数创建类的实例,正确初始化引用计数器,并创建和返回指向它的智能指针。如果您为OdRxObjectImpl模板创建的实例创建智能指针,则智能指针将更改引用计数器。

OdStaticRxObject template

OdStaticRxObject模板为派生自OdRxObject类的类创建addRef()和release()方法的空实现。当对象在程序范围内声明时创建静态实例,当对象放弃自己的范围时自动销毁静态实例。程序不能丢失为静态实例分配的内存。因此,静态实例不需要引用计数器。OdStaticRxObject模板包装了指定的类,并创建了addRef()和release()方法的空实现。numRefs()方法返回1。如果您为OdStaticRxObject模板创建的实例创建智能指针,那么智能指针将不会更改引用计数器。
要将OdStaticRxObject模板用于动态实例,必须在派生自OdRxObject类的指定类中实现新的和删除操作符。可以使用ODRX_HEAP_OPERATORS宏(它在指定的类中创建新的和删除操作符的标准实现),也可以使用ODRX_USING_HEAP_OPERATORS宏(它从父类继承新的和删除操作符的实现)。OdRxObjectImpl模板使用ODRX_HEAP_OPERATORS宏自动定义新的和删除操作符。

OdRxObjectPtr class and OdSmartPtr template

OdRxObjectPtr类实现了非类型化的智能指针,它可以控制从OdRxObject基类派生的任何类的实例。您可以立即在您的程序中创建这个类的实例,即智能指针,并为它们分配任何实例的地址。缺少类型控件。
OdSmartPtr模板为指定的类实现了类型化的智能指针。您必须在(typedef)语句中使用这个类来定义用于在程序中创建智能指针的智能指针类型。当您使用定义类型的智能指针执行不同的操作时,它们会检查类类型并在类型不同时生成异常。所有数据库类都有相应的带“Ptr”后缀的类型化智能指针类,例如OdDbCirclePtr类是指向OdDbCircle类实例的智能指针。
OdRxObjectPtr和OdSmartPtr实现智能指针的基本功能:附加一个实例对象的智能指针,分离实例智能指针的分配智能指针,比较两个智能指针,检查NULL,引用的对象的地址,得到属性引用的对象,调用方法的对象引用,引用的对象的引用计数,并摧毁时引用的对象引用计数器变成零。
OdBaseObjectPtr类是OdSmartPtr模板的基类,它实现了基本的智能指针操作:获取原始指针并检查空值。
如果使用得当,智能指针类有助于确保堆对象的正确管理,无论是在正常执行情况下,还是在异常将控制转移到当前范围之外的情况下。

Creating an Empty Implementation of the Reference Counter

OdStaticRxObject模板类用于创建在程序使用指向实例的智能指针进行操作时不计算引用的类及其实例。该模板创建了基类的addRef()和release()虚方法的空实现,并且没有在类中创建引用计数器。当您在自动或静态内存中创建实例、为实例分配动态内存或从指定的类派生新类时,可以将此模板用作类的包装。
如果希望为静态实例创建自己的类,可以使用以下类定义从OdRxObject基类派生类:

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

与类定义一起,使用OdSmartPtr模板声明类的智能指针类型:

typedef OdSmartPtr<MyObj> MyObjPtr;

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

OdStaticRxObject<MyObj> my;

如果你想为动态实例使用自己的类,在类定义中添加ODRX_HEAP_OPERATORS宏来创建新操作符和删除操作符的标准实现:

class MyObj : public OdRxObject
{
 public:
   ODRX_HEAP_OPERATORS();

 public:
   MyObj();
   ~MyObj();
};

要在动态内存中创建实例,请在代码中声明类类型的原始指针,并在(new)操作符中使用OdStaticRxObject模板:

MyObj* pMy = new OdStaticRxObject<MyObj>;

如果您希望在所有派生自您自己的类的类中插入智能指针功能,那么可以直接从OdStaticRxObject模板派生类,并在类定义中添加ODRX_HEAP_OPERATORS

class MyObj : public OdStaticRxObject<OdRxObject>
{
 public:
   ODRX_HEAP_OPERATORS();

 public:
   MyObj();
   ~MyObj();
};

若要在自动或静态内存中创建实例,请在没有模板的情况下为类类型声明一个变量:

MyObj my;

要在动态内存中创建实例,声明一个指向类类型的指针并使用(new)操作符,但不使用模板:

MyObj* pMy = new MyObj;

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

MyObjPtr pSmart0 = &my;
MyObjPtr pSmart1 = pMy;
MyObjPtr pSmart2 = new OdStaticRxObject<MyObj>;
MyObjPtr pSmart3 = new MyObj;

如果创建了动态实例,则必须使用(delete)操作符删除它,否则会发生内存泄漏。

delete pMy;

Using an Empty Implementation of the Reference Counter

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

class MyObj : public OdRxObject
{
 public:
   ODRX_HEAP_OPERATORS();

 public:
   MyObj();
   ~MyObj();
};

typedef OdSmartPtr<MyObj> MyObjPtr;

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

void TestStaticInstance()
{
   OdStaticRxObject<MyObj> my;

   RefCountTest(&my);

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

void TestDynamicInstance()
{
   MyObj* pMyObj = new OdStaticRxObject<MyObj>;

   RefCountTest(pMyObj);

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

   delete pMyObj;
}

要为所有派生自您自己的类的类插入智能指针功能,您必须通过OdStaticRxObject模板从OdRxObject类派生类,当您定义它时:

class MyObj : public OdStaticRxObject<OdRxObject>
{
 public:
   ODRX_HEAP_OPERATORS();

 public:
   MyObj();
   ~MyObj();
};

typedef OdSmartPtr<MyObj> MyObjPtr;

在声明变量时,不需要在代码中使用OdStaticRxObject模板。测试功能将有以下实现:

void TestStaticInstance()
{
   MyObj my;

   RefCountTest(&my);

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

void TestDynamicInstance()
{
   MyObj* pMyObj = new MyObj;

   RefCountTest(pMyObj);

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

   delete pMyObj;
}

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: 1

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

3.(pSmart2)=NULL
  Reference counter: 1

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

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

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

Return from RefCountTest()
  Reference counter: 1

Object is destroyed

Return from Test

当测试函数创建MyObj类的实例时,实例的引用计数器将获得值1。当函数将实例的地址设置为任何智能指针时,引用计数器不会更改自己的值。当TestStaticInstance()函数结束时,它会自动销毁与引用计数器值无关的静态实例。当TestDynamicInstance()函数结束时,引用计数器为1,智能指针不能自动销毁实例。要删除动态实例,测试函数直接调用delete操作符。

Reference:
https://www.opendesign.com

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

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

昵称

取消
昵称表情代码图片

    暂无评论内容