美文网首页bentley开发C++ 2a
EditElementHandle用法和思考

EditElementHandle用法和思考

作者: 左图右码 | 来源:发表于2022-03-13 12:07 被阅读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中大部分的类都不是完整的(暴力阉割),当你以左值使用它的时候,编译器会用默认的方式,按完整的类的声明的方式按字节拷贝,不完整的类的内存布局本身就是错的,这太危险了(汗流浃背。。。)

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

    相关文章

      网友评论

        本文标题:EditElementHandle用法和思考

        本文链接:https://www.haomeiwen.com/subject/riprdrtx.html