淺談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("\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對象.

符號表,符號表記錄均有類似的智能指針操作,大同小異.不再敘述.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM