• 浅谈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对象.

    符号表,符号表记录均有类似的智能指针操作,大同小异.不再叙述.

  • 相关阅读:
    企业微信自建应用使用审批流程引擎
    unicode和utf8互转【转】
    禅道迅捷版,人人都可用的项目管理工具!
    《2021年IT行业项目管理调查报告》重磅发布!
    wxpython窗体之间传递参数
    go Print 和 反射
    go 接口学习笔记
    设计模式学习笔记
    go 变量逃逸分析
    Go ASM 学习笔记之 ppt 版
  • 原文地址:https://www.cnblogs.com/edata/p/12643930.html
Copyright © 2020-2023  润新知