前言
用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對象.
符號表,符號表記錄均有類似的智能指針操作,大同小異.不再敘述.