EditElementHandle用法和思考
其实我不愿意写有关microstation的代码,有点专,有点窄,API有点糙,甚至很多与经典范式和准则都是背道而驰的,永远看上去像个半成品,仅仅用它当成解释目标议题的样例来看吧。
借助EditElementHandle/ElementHandle,程序员可以摆脱了危险的指针(MSElmdscrP,C的遗产)操作,在多个退出条件不用都进行手工的free,这是得益于大名鼎鼎的RAII,这是C++进行资源管理的标准范式。
但是还有那么一点点不适,你可能还不能那些随心所欲:
//EditElementHandle节选
struct EditElementHandle : public ElementHandle
{
private:
EditElementHandleR operator= (EditElementHandleCR from); // illegal!!
explicit EditElementHandle (ElementHandleCR from); // illegal!!
explicit EditElementHandle (EditElementHandleCR from); // illegal!!
public:
EditElementHandle() {}
EditElementHandle (MSElementDescrP descr, bool owned, bool isUnmodified, DgnModelRefP modelRef=NULL) {}
EditElementHandle (ElementRefP elRef, DgnModelRefP modelRef=NULL) : ElementHandle (elRef, modelRef) {}
EditElementHandle (MSElementCP el, DgnModelRefP modelRef) : ElementHandle (el, modelRef){}
EditElementHandle (ElementId id, DgnModelRefP modelRef) : ElementHandle (id, modelRef) {}
EditElementHandle (ElementHandleCR from, bool duplicateDescr);
void Duplicate (ElementHandleCR);
...
有几个私有的未实现的复制构造和赋值构造函数。说明这个struct不能作为左值存在,下面的代码是不能通过编译的:
EditElementHandle EditElementHandleFromId(ElementID id)
{
//do something...
return EditElementHandle(id,ACTIVEMODEL);
}
error C2440: “return”: 无法从“Bentley::DgnPlatform::EditElementHandle”转换为“Bentley::DgnPlatform::EditElementHandle”
note: struct“Bentley::DgnPlatform::EditElementHandle”的构造函数声明为“explicit”
不能如标准类型,比如int,double,std::string...那么丝滑,有点反直觉。
有几种变通的方法,比如传参后,调用placement new,开销没有增加:
void EditElementHandleFromId(EditElementHandle& eeh, ElementId id)
{
::new(&eeh)EditElementHandle(id, ACTIVEMODEL);
}
我常用的最优雅的方法就是借助智能指针了:
auto EditElementHandleFromId(ElementId id)
{
return std::make_shared<EditElementHandle>(id, ACTIVEMODEL);
}
因为它可以以左值的方式出现。
调用不同的构造方式构建,然后直接返回,中间的临时变量都不需要了:
std::shared_ptr<EditElementHandle> QCPGraphDataHelper::createSectionFromPlot(QCustomPlot& plot)
{
MSElementDescrP edp = nullptr;
//...some code there
return std::make_shared<EditElementHandle>(edp,true,false,ACTIVEMODEL);
}
主要是优雅、骨感(一个朋友经常用这个词评价代码)。。。
因为这样的限制,EditElementHandle也不能直接放入标准容器,所以MDLAPI提供了一个专用的容器ElementAgenda,同样,你思考一下,这个容器能不能以左值存在?下面的代码居然是可以通过编译的:
ElementAgenda getAgenda()
{
return ElementAgenda();
}
非常符合编码的直觉和手感,但如果你以左值使用它,会导致系统的崩溃。因为接口并没有在dll中导出这两个函数:
ElementAgenda& operator == (ElementAgenda const&);
ElementAgenda(ElementAgenda const&);
它并不是个完整的类,mdl Api中大部分的类都不是完整的(暴力阉割),当你以左值使用它的时候,编译器会用默认的方式,按完整的类的声明的方式按字节拷贝,不完整的类的内存布局本身就是错的,这太危险了(汗流浃背。。。)
你可能已经猜到如何在左值的情况下使用它了。。。