zoukankan      html  css  js  c++  java
  • 浅谈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对象.

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

  • 相关阅读:
    几个新角色:数据科学家、数据分析师、数据(算法)工程师
    人类投资经理再也无法击败电脑的时代终将到来了...
    Action Results in Web API 2
    Multiple actions were found that match the request in Web Api
    Routing in ASP.NET Web API
    how to create an asp.net web api project in visual studio 2017
    网站漏洞扫描工具
    How does asp.net web api work?
    asp.net web api history and how does it work?
    What is the difference between a web API and a web service?
  • 原文地址:https://www.cnblogs.com/edata/p/12643930.html
Copyright © 2011-2022 走看看