天气与日历 切换到窄版

 找回密码
 立即注册
中国膜结构网
十大进口膜材评选 十大国产膜材评选 十大膜结构设计评选 十大膜结构公司评选
查看: 62|回复: 0

浅谈ObjectARX智能指针AcDbObjectPointer的用法

[复制链接]

该用户从未签到

主题

0

回帖

2912

积分

管理员

积分
2912
发表于 2024-6-22 09:46:18 | 显示全部楼层 |阅读模式
前言

用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("\n打开对象失败!,错误码: %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("\n创建对象失败!,错误码: %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("\n打开块表失败!,错误码: %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("\n打开块表记录失败!,错误码: %s"),acadErrorStatusText(pBlkRcd.openStatus()));
                return;
        }
        es = pBlkRcd->appendAcDbEntity(pCircle);
        if (Acad::eOk == es)
        {
                acutPrintf(_T("\n添加实体成功!"));
        }
}
  我可以看到,以上代码没有使用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的用法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|中国膜结构网|中国膜结构协会|进口膜材|国产膜材|ETFE|PVDF|PTFE|设计|施工|安装|车棚|看台|污水池|中国膜结构网_中国空间膜结构协会

GMT+8, 2024-11-1 10:29 , Processed in 0.174725 second(s), 28 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表