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