浅谈ObjectARX智能指针AcDbObjectPointer的用法
Posted edata
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈ObjectARX智能指针AcDbObjectPointer的用法相关的知识,希望对你有一定的参考价值。
前言
用ARX智能指针打开对象,可以不在乎是否close,
但同时也要注意这个变量的作用域(生命周期)问题,
ARX智能指针,他的原理是利用类的析构造函数特性自动关闭对象.
这里的智能指针指的是AcDbObjectPointer这一类使用AcDbObjectPointerBase基类派生的类模板统称.
下面是打开示例.
void testOpen() { ads_point pt; ads_name ent; if (RTNORM != acedEntSel(NULL,ent,pt)) { return; } AcDbObjectId objId; acdbGetObjectId(objId,ent); //使用ARX智能指针打开对象,实体类对象可以使用这种方式直接打开. AcDbObjectPointer<AcDbBlockReference> pBlkRef(objId,AcDb::kForRead); //判断是否打开成功 //注意ARX智能指针使用智能指针成员函数的时候是点符号"."不是指针符号"->" if (Acad::eOk != pBlkRef.openStatus()) { //根据情况做打开失败处理 acutPrintf(_T(" 打开对象失败!,错误码: %s"),acadErrorStatusText(pBlkRef.openStatus())); return; //continue; //break; } //打开成功,可以使用对象的指针了注意是指针"->"符号. AcGePoint3d ptInsert2 = pBlkRef->position(); //智能指针打开,close再是必须的处理. //close可以多次执行,某些特殊情况,智能指针也需要手动close,所以不会出问题. //下面示意创建一个新的对象. //先声明pCircle对象 AcDbObjectPointer<AcDbCircle> pCircle; //再创建实体对象,相当于new AcDbCircle Acad::ErrorStatus es= pCircle.create(); //判断是否创建成功 if (Acad::eOk != es) { acutPrintf(_T(" 创建对象失败!,错误码: %s"),acadErrorStatusText(es)); return; } //设置圆的属性 pCircle->setCenter(ptInsert2); pCircle->setRadius(500.0); //下面同样使用智能指针的方式打开模型空间添加实体 AcDbDatabase *pDb=acdbHostApplicationServices()->workingDatabase(); //打开块表 AcDbBlockTablePointer pBlkTbl(pDb,AcDb::kForRead); if (Acad::eOk != pBlkTbl.openStatus()) { acutPrintf(_T(" 打开块表失败!,错误码: %s"),acadErrorStatusText(pBlkTbl.openStatus())); return; } //先获取模型空间的ID AcDbObjectId mSpaceId; pBlkTbl->getAt(ACDB_MODEL_SPACE,mSpaceId); //打开块表记录方式一 AcDbBlockTableRecordPointer pBlkRcd(mSpaceId,AcDb::kForWrite);
//打开块表记录方式二(这种直接用AcDbDatabase参数打开到模型空间块表记录,可以省略打开块表)
//AcDbBlockTableRecordPointer pBlkRcd(ACDB_MODEL_SPACE,pDb,AcDb::kForWrite); if (Acad::eOk != pBlkRcd.openStatus()) { acutPrintf(_T(" 打开块表记录失败!,错误码: %s"),acadErrorStatusText(pBlkRcd.openStatus())); return; } es = pBlkRcd->appendAcDbEntity(pCircle); if (Acad::eOk == es) { acutPrintf(_T(" 添加实体成功!")); } }
我可以看到,以上代码没有使用close来关闭打开的对象.其原理就是用AcDbObjectPointer打开对象在释放这个变量的时候,利用析构函数来close或者delete处理,
简单看下这个类模板的析构函数.
选择AcDbObjectPointer 按F12转到定义,他的基类为AcDbObjectPointerBase,我们找这个类的析构函数
template<class T_OBJECT> class AcDbObjectPointer : public AcDbObjectPointerBase<T_OBJECT> { public: AcDbObjectPointer(); AcDbObjectPointer(AcDbObjectId objId, AcDb::OpenMode mode = AcDb::kForRead, bool openErased = false); #if DBOBJPTR_EXPOSE_PTR_REF AcDbObjectPointer(T_OBJECT * pObject); void operator=(T_OBJECT *pObject); #endif Acad::ErrorStatus open(AcDbObjectId objId, AcDb::OpenMode mode = AcDb::kForRead, bool openErased = false); private: // Copy and assignment prohibited. AcDbObjectPointer(const AcDbObjectPointer &) = delete; AcDbObjectPointer& operator=(const AcDbObjectPointer &) = delete; }; typedef AcDbObjectPointer<AcDbDictionary> AcDbDictionaryPointer; typedef AcDbObjectPointer<AcDbEntity> AcDbEntityPointer;
析构函数.
template<class T_OBJECT> inline AcDbObjectPointerBase<T_OBJECT>::~AcDbObjectPointerBase() { if (m_ptr != NULL) { assert(m_status == Acad::eOk); Acad::ErrorStatus closeStatus = closeInternal(); (void)closeStatus; assert(closeStatus == Acad::eOk); } }
关键的函数是closeInternal()
下面是源码
template<class T_OBJECT> inline Acad::ErrorStatus AcDbObjectPointerBase<T_OBJECT>::closeInternal() { if (m_ptr == NULL) return Acad::eOk; Acad::ErrorStatus es = Acad::eOk; if (m_ptr->objectId().isNull()) { delete m_ptr; es = Acad::eOk; } else { es = m_ptr->close(); } m_ptr = NULL; m_status = Acad::eNullObjectPointer; return es; }
我们可以看到,如果没有加入到数据库,也就是对象Id为空,就直接delete释放对象.否则就执行close处理.
以上就是arx智能指针的浅析.
下面这几个智能指针的成员函数比较常用
Acad::ErrorStatus openStatus() const; Acad::ErrorStatus open(AcDbObjectId objId, AcDb::OpenMode mode = AcDb::kForRead, bool openErased = false); Acad::ErrorStatus acquire(T_OBJECT *& pObjToAcquire); Acad::ErrorStatus release(T_OBJECT *& pReleasedObj); Acad::ErrorStatus close(); Acad::ErrorStatus create();
open()不需要多说.就是打开对象.
openStatus()存放打开状态的记录值,
acquire() 这个是可以把已经用其他方式打开的对象,比如用acdbOpenAcDbEntity打开的对象转换为智能指针对象,
这样就可以不需要刻意处理close,再比如你clone克隆的实体,偏移的实体,打断的实体,也可以转换到智能指针方式.
release()释放对象,和acquire应该是相反的操作,就是把对象转给普通指针处理,不再自动close处理.
close()关闭对象,调用closeInternal();不是简单close,注意智能指针的pEnt.close()和pEnt->close();这不是同一个函数.
create(),创建对象,就是new对象.
符号表,符号表记录均有类似的智能指针操作,大同小异.不再叙述.
以上是关于浅谈ObjectARX智能指针AcDbObjectPointer的用法的主要内容,如果未能解决你的问题,请参考以下文章
C++11之智能指针(unique_ptrshared_ptrweak_ptrauto_ptr)浅谈内存管理