ObjectARX 智能指针
AcDbObjectPointer
class AcDbObjectPointer;
typedef AcDbObjectPointer<AcDbDictionary> AcDbDictionaryPointer;
typedef AcDbObjectPointer<AcDbEntity> AcDbEntityPointer;
AcDbSymbolTablePointer
typedef AcDbSymbolTablePointer<AcDbBlockTable> AcDbBlockTablePointer;
typedef AcDbSymbolTablePointer<AcDbDimStyleTable> AcDbDimStyleTablePointer;
typedef AcDbSymbolTablePointer<AcDbLayerTable> AcDbLayerTablePointer;
typedef AcDbSymbolTablePointer<AcDbLinetypeTable> AcDbLinetypeTablePointer;
typedef AcDbSymbolTablePointer<AcDbRegAppTable> AcDbRegAppTablePointer;
typedef AcDbSymbolTablePointer<AcDbTextStyleTable> AcDbTextStyleTablePointer;
typedef AcDbSymbolTablePointer<AcDbUCSTable> AcDbUCSTablePointer;
typedef AcDbSymbolTablePointer<AcDbViewTable> AcDbViewTablePointer;
typedef AcDbSymbolTablePointer<AcDbViewportTable> AcDbViewportTablePointer;
AcDbSymbolTableRecordPointer
typedef AcDbSymbolTableRecordPointer<AcDbBlockTableRecord>
AcDbBlockTableRecordPointer;
typedef AcDbSymbolTableRecordPointer<AcDbDimStyleTableRecord>
AcDbDimStyleTableRecordPointer;
typedef AcDbSymbolTableRecordPointer<AcDbLayerTableRecord>
AcDbLayerTableRecordPointer;
typedef AcDbSymbolTableRecordPointer<AcDbLinetypeTableRecord>
AcDbLinetypeTableRecordPointer;
typedef AcDbSymbolTableRecordPointer<AcDbRegAppTableRecord>
AcDbRegAppTableRecordPointer;
typedef AcDbSymbolTableRecordPointer<AcDbTextStyleTableRecord>
AcDbTextStyleTableRecordPointer;
typedef AcDbSymbolTableRecordPointer<AcDbUCSTableRecord>
AcDbUCSTableRecordPointer;
typedef AcDbSymbolTableRecordPointer<AcDbViewTableRecord>
AcDbViewTableRecordPointer;
typedef AcDbSymbolTableRecordPointer<AcDbViewportTableRecord>
AcDbViewportTableRecordPointer;
例子
AcDbBlockTableRecordPointer curSpace(
curDoc()->database()->currentSpaceId(),
AcDb::kForWrite);
if (curSpace.openStatus() == Acad::eOk)
{
...
}
AcDbObjectPointer<AcDbLine> line;
line.create();
line->setStartPoint(AcGePoint3d(0, 0, 0));
line->setEndPoint(AcGePoint3d(10, 10, 0));
AcDbBlockTableRecordPointer curSpace(
acDocManager->curDocument()->database()->currentSpaceId(),
AcDb::kForWrite);
if (curSpace.openStatus() == Acad::eOk)
{
curSpace->appendAcDbEntity(line);
}
//这个例子在AcDbEntity添加扩展字典数据,使用AcDbEntityPointer 、AcDbDictionaryPointer 、AcDbObjectPointer<AcDbXrecord> 这些类实例销毁时,自动关闭Arx实体/对象,且不用担心中间代码抛出异常。
bool SetEntityDictFromRbChain(AcDbObjectId entId,ACHAR *strDictName,resbuf* pRbValue)
{
AcDbEntityPointer pObj(entId,AcDb::kForWrite);
if (pObj.openStatus()!=Acad::eOk ) return false;
AcDbObjectId extDictId = pObj->extensionDictionary();
if (extDictId == AcDbObjectId::kNull)
{
Acad::ErrorStatus es = pObj->createExtensionDictionary();
if (es != Acad::eOk) return false;
if ((extDictId = pObj->extensionDictionary()) == AcDbObjectId::kNull)
return false;
}
AcDbDictionaryPointer pDict(extDictId,AcDb::kForRead);
if(pDict.openStatus() != Acad::eOk)
return false;
AcDbObjectId xRecId;
if(pDict->getAt(strDictName,xRecId) != Acad::eOk)
{
AcDbXrecord* pXrec = new AcDbXrecord();
//pXrec 可以使用scoped_ptr
pDict->upgradeOpen();
if(pDict->setAt(strDictName,pXrec,xRecId) != Acad::eOk)
{
delete pXrec;
return false;
}
pXrec->close();
}
AcDbObjectPointer<AcDbXrecord> pXrcord(xRecId,AcDb::kForWrite);
if(pXrcord.openStatus() != Acad::eOk) return false;
if(pXrcord->setFromRbChain(*pRbValue) != Acad::eOk) return false;
acutRelRb(pRbValue);
return true;
}
Automatic closing of AutoCAD objects withObjectARX SmartPointers(用 ObjectARX的智能指针自动关闭AutoCAD物体)
Thank you to Fenton Webb, from DevTech Americas, for writing this articlefor the recently published ADN Platform Technologies Customization Newsletter.This article also talks about the new AcDbSmartObjectPointer class referencedin this overview of the new APIs in AutoCAD 2009.*
谢谢你 ,balala…..
Thoseof us who regular create ObjectARX code to manipulate the AutoCAD drawingdatabase are fully aware of the mechanism for opening an object for read (tosimply access data held inside it) or write (to update it with new data). Ohand I almost forgot - followed by a call to close() when you are done.
那些死板地用Objectarx代码来操纵AutoCAD图形数据库都很担心打开一个物体去读取(仅仅为了读取里面的数据)或者写(更新数据)的操作。哦,我几乎总是忘记-当你完成之后要调用close()函数。
Buthere lies a very common problem illustrated by that last sentence; the problemsstart when you accidentally forget to close an object once you are finishedwith it. AutoCAD follows a strict set of rules which allows the checking-in/outof data inside of AutoCAD and these rules must be adhered to. If not, thenAutoCAD will abort in order to do its best to save the previous valid state ofthe database.
但是像上面最后一句那样,这里存在一个普遍的问题。问题开始于你完成后却不经意忘记去关闭一个物体,而AutoCAD遵循一系列的严格的规则以允许检查和记录AutoCAD内部数据的,而且这些规则必须遵守。如不这样,为了最好地保存先前的有效的数据库状态,AutoCAD将会中止。
“Youmust be very careful to close your objects when you are finished with them”.It’s very easy for me to say that, but even I, the person shaking his fingersaying those infamous words will fail to remember my own advice time and timeagain, this is why using ObjectARX SmartPointers is a MUST.
Solet’s look at this thing in ObjectARX called SmartPointers.
“当你使用完后,你必须很小心地关闭那些物体”。我说起来容易,但是即使我-那个指指点点说这些无耻的话的人-依然会屡次不记得我自己的建议。这个正是我们为什么必须用ObjectARX智能指针的原因。
那么,我们来看看关于ObjectARX的智能指针。
Whatare they? First take a look at the MSDN article on “Template Classes” asthis explains the basic concept. Leading on from that article, and now in myown words, ObjectARX SmartPointers are C++ template classes which wrap anunderlying AutoCAD AcDbObject derived class pointer, and simply providesautomatic closure of that pointer, if valid, on destruction of the ObjectARXSmartPointer class (so the end of a function or closing brace “}”).
它们是什么?首先看一下MSDN的关于“模板类”的文章,它解释了基本概念。
根据这篇文章,现在用我自己的话来说,ObjectARX 智能指针是一个C++模板类,它封装在 AutoCAD AcDbObject派生的类指针里,当一个有效的ObjectARX智能指针类在析构时,能自动关闭.(函数的末尾或者封闭的花括号“}”)
Aquestion that often arises is on the usage of this class, in particular the wayto access the member functions. The template class itself has been implementedso that if you reference a member function with the dot “.” operator
经常被提及的问题是关于这个类的用法,以特别的方式去接口成员函数。模板类本身已提供了方法,所以你如果引用成员函数用点 “.” 操作符即可。
line.openStatus()
then,you reference the ObjectARX SmartPointer specific functions. If you reference amember function with the arrow “->” operator
然后,你用ObjectARX 智能指针的某个函数。如果你用“->”操作符来引用某个成员函数,
line->setStartPoint()
Then,because the arrow operator has been overridden to return the underlyingAcDbObject pointer, you simply reference the underlying AcDbObject derivedclass, in this case the AcDbLine::setStartPoint().
Sohow do we use them then…? Let’s start by showing old ObjectARX code which addsan AcDbLine to the Current Space using open and close.
因为箭头操作符已被重载返回封装的AcDbObject指针,你只不过引用了封装的AcDbObject派生类。如
AcDbLine::setStartPoint().
那么我们怎么用它…?让我们先看如下所示的老式做法的ObjectARX代码:
打开当前空间,增加一条AcDbLine后关闭。
// create a new line
AcDbLine *line = new AcDbLine();
// set the properties for it
line->setStartPoint(AcGePoint3d(10,10,0));
line->setEndPoint(AcGePoint3d(20,30,0));
// now add it to the current space
AcDbBlockTableRecord *curSpace = NULL;
// open the current space for write
Acad::ErrorStatus es =
acdbOpenObject(
(AcDbBlockTableRecord *&)curSpace,
curDoc()->database()->currentSpaceId(),
AcDb::kForWrite
);
// if ok
if (es == Acad::eOk)
{
// add it to the space
es = curSpace->appendAcDbEntity(line);
// check that everything was ok
if (es != Acad::eOk)
{
delete line;
return;
}
// now close everything
line->close();
curSpace->close();
}
It'sthe 2 close statements at the end which are, first of all, very easy to forgetto put in, but also notice they return just before which indicates a very rarefailure, but just as importantly (and erroneously) bypasses the close ofcurSpace.
Thisis where ObjectARX SmartPointers not only provide automatic closure and cleanupbut also peace of mind…
Let’stake a look at the same code, but this time using ObjectARX SmartPointers.
这里在末尾有两个close语句,首先,我们很容易忘记放进去,同时也注意到
放在它们之前的一个return语句,表示很少有的错误导致函数返回。(注释:这个return语句前应该加curSpace->close();) 忽略关闭curSpace不仅严重而且错误。
这个地方用ObjectARX 智能指针不仅能提供自动关闭和清理,同时也带给我们内心的宁静。
现在让我们看看同样的事情,这次用ObjectARX智能指针来实现。
// create a new line 用智能指针创建一个AcDbLine物体
AcDbObjectPointer<AcDbLine> line;
line.create();
// set the properties for it
line->setStartPoint(AcGePoint3d(10,10,0));
line->setEndPoint(AcGePoint3d(20,30,0));
// now add it to the current space
AcDbBlockTableRecordPointer
curSpace(
curDoc()->database()->currentSpaceId(),
AcDb::kForWrite
);
// if ok
if (curSpace.openStatus() == Acad::eOk)
{
Acad::ErrorStatus es =curSpace->appendAcDbEntity(line);
// check that everything was ok
if (es != Acad::eOk)
{
// no need for a delete as the smartpointer does this forus
//不需要删除智能指针
return;
}
}
// everything will be closed automatically for us
//所有的会为我们自动关闭
Notonly is this ObjectARX code "close" safe, it is also memoryleak-safe. Also, look how much tidier it is. Much more friendly in my opinion!
Here’ssome more SmartPointer code which selects an Entity on screen and opens it forread, just as an example.
不仅仅这个ObjectARX代码是安全的,而且内存也是安全释放。现在看起来也是相当整洁。依我看来是友好多了。
这里还有一些智能指针的代码,在屏幕上选择一个实体,打开后读取它,如代码:
ads_name ename;
ads_point pt;
// pick an entity to check
int res = acedEntSel (_T("\nPick a Line : "), ename, pt);
// if the user didn't cancel
if (res == RTNORM)
{
AcDbObjectId objId;
// convert the ename to an object id
acdbGetObjectId (objId, ename);
// open the entity for read
AcDbObjectPointer<AcDbLine>ent (objId, AcDb::kForRead);
// if ok
if (ent.openStatus () == Acad::eOk)
{
AcGePoint3d startPnt;
ent->startPoint(startPnt);
// do something
}
}
Butwhat if you have reams and reams of existing code using old-style open andclose, and you want to migrate to ObjectARX Smart Pointers with the leastamount of effort? Well, we’ve tried to make it easy for you. Since ObjectARX2007, in dbobjptr.h simply uncomment the #define DBOBJPTR_EXPOSE_PTR_REF andnow life should be easy! (Well, with one exception - see **NOTE below).
Here’sthe converted version of the original code we used at the beginning, convertingto use ObjectARX SmartPointers couldn’t be easier (I’ve highlighted the changesin bold).
但是如果你有一大堆一大堆旧式的现存代码,你像把ObjectARX智能指针合成进去,你不得花大把精力?好了,我们尽力使你弄起来容易些。自从ObjectARX 2007,在dbobjptr.h简单地取消注释#defineDBOBJPTR_EXPOSE_PTR_REF
现在活儿就变得So easy了!(不过,有一条例外,看下面的注释)
这里是我们开始用的原先代码的转换版。转换为ObjectARX 智能指针不会更容易些。(我已经用粗体字突出显示了 修改部分)
// create a new line
AcDbObjectPointer<AcDbLine> line = new AcDbLine();
// set the properties for it
line->setStartPoint(AcGePoint3d(10,10,0));
line->setEndPoint(AcGePoint3d(20,30,0));
// now add it to the current space
AcDbBlockTableRecordPointer curSpace = NULL;
// open the current space for write
Acad::ErrorStatus es =
acdbOpenObject((AcDbBlockTableRecord *&)curSpace,
curDoc()->database()->currentSpaceId(),
AcDb::kForWrite
);
// if ok
if (es == Acad::eOk)
{
// add it to the space
es = curSpace->appendAcDbEntity(line);
// check that everything was ok
if (es != Acad::eOk)
{
delete line;
return;
}
// now close everything
line->close();
curSpace->close();
}
Noticethat I didn’t bother to remove the two close() calls at the end, there’s noneed. If you close them by hand, or forget, it’s all good with ObjectARXSmartPointers.
注意:我并没有去费力删除结尾处两条close()调用,这个地方不需要。如果你手动关闭或者忘记了,对ObjectARX智能指针都是可以的。
**NOTE:So, in order to get the acdbOpenObject to accept the same code as before, indbobjptr.h, at line 467 (ObjectARX 2009 SDK), there is an assert which needs tobe omitted; either #define NDEBUG or I recommend that you simply change theassert to be enclosed by the #ifndef DBOBJPTR_EXPOSE_PTR_REF
注释:所以,为了能使acdbOpenObject能像先前一样接受相同的代码,在dbobjptr.h文件,467行(ObjectARX 2009 SDK),那里有个断言需要删除,同样,
#defineNDEBUG 或我推荐你仅仅改变包在#ifndef DBOBJPTR_EXPOSE_PTR_REF为如下断言:
AcDbObjectPointerBase<T_OBJECT>::object(){
#ifndef DBOBJPTR_EXPOSE_PTR_REF
assert(m_status == Acad::eOk);
#endif // DBOBJPTR_EXPOSE_PTR_REF
Lastbut not the least is the new AcDbSmartObjectPointer template class in ObjectARX2009, defined in the header file dbobjptr2.h.
最后却不是最小的新的 AcDbSmartObjectPointer模板类 出现在objectARX2009,定义在dbojbptr2.h的这个头文件中。
Thisnew template class works in the same way as AcDbObjectPointer template classexcept that it works by NOT opening an object at all if its open state isalready what was requested, or even closing an object multiple times beforeopening in the desired manner. It merely hands you the already opened objectpointer for your use. This means that it is much more efficient and also muchmore powerful in its usage. It also treats kForNotify and kForRead in the samemanner, which is effectively kForRead.
这个新的模板类跟AcDbObjectPointer模板类一样的方式,一样的作用,除了它
如果处于已打开状态就不能再打开一个物体,或甚至在以想要的方式打开前多次关闭一个物体。这只不过传给你一个已经打开的物体指针给你用。这意味着它更有效地更强大的用途。它同时也以相同方式处理kForNotify和kForRead,是有效率的kForRead.
Onefeature of this new SmartPointer class that I’d like to talk about is theability to multiply open an object for write, from different places, at thesame time, a bit like a Transaction can – this is extremely powerful when youthink about it.
我要说的新的智能指针类的一个特性是:能同时从不同地方多重打开一个物体以写入,这个有点像Transaction 。这是极其强大的。
Atthe same time though, I find thinking about the power that this can provide canstart generating some other complex thoughts and scenarios that maybe we shouldbe cautious of; the bottom line is that you should be very careful aboutmultiply opening an object for write no matter how good the class that controlsit.
同时,我在想它所提供的能力时生成其它一些复杂的顾虑和情况是我们应当注意的,底线是当你以写方式重复打开一个物体时,你应当小心,不管这个类如何好控制。
Anexample of where this type of functionality really might be useful to usdevelopers is in say an Object Reactor callback. Quite often you might want tomodify the current object’s state but of course you can’t because it is alreadyopen for notify. Using this new SmartPointer class it makes it possible tomodify the object as you see fit in this context, but be careful to handle therecursive object modified notifications that will be fired by doing this.
这类功能能真正对我们有用的地方的一个例子是物体反应器回调。你也许要相当频繁修改当前物体状态,但是当然你不能,因为它已经打开为回调用。用这个新的智能指针类,在这样情况下就使得修改你所见物体变得可能,但是应当注意处理做这事带来的循环物体修改通知。
All in all a very exciting new addition to the ObjectARX API, make sureyou check it out.
总的来说,这是ObjectARX API一个非常激动人心的新加功能 ,相信你能体验它。