bentley开发C++ 2a

EditElementHandle用法和思考

2022-03-13  本文已影响0人  左图右码

其实我不愿意写有关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中大部分的类都不是完整的(暴力阉割),当你以左值使用它的时候,编译器会用默认的方式,按完整的类的声明的方式按字节拷贝,不完整的类的内存布局本身就是错的,这太危险了(汗流浃背。。。)

你可能已经猜到如何在左值的情况下使用它了。。。

上一篇下一篇

猜你喜欢

热点阅读