我正在将一些图形代码从Python(networkx)移植到C++(BGL)。在我的Python代码中,图形的顶点和边缘是客户端定义的对象,它们实现了已建立的接口(interface);我继续对它们调用一堆方法。一切顺利。
天真的,BGL似乎旨在支持具有“ bundle 属性”的类似设计模式。这些基本上允许通过传递某些模板参数来定义顶点和边的自定义类型:
adjacency_list<OutEdgeList, VertexList,
Directed, VertexProperties,
EdgeProperties, GraphProperties,
EdgeList>
此处的自定义顶点和边类型由
VertexProperties
和EdgeProperties
给出。在该端口上工作时,我注意到了几件事,使我认为BGL的 bundle 属性接口(interface)实际上仅旨在支持(或多或少)不可变的类型:
如果您将某些内容放入图表中,则会获得一个“描述符”,您必须使用该“描述符”从那里开始引用它。有用于边缘和顶点的描述符,它们是图形的“键”(实现为不可变的)。因此,如果您有一个顶点并且要查找相邻的顶点,则必须(a)获取当前的顶点描述符,(b)使用BGL方法查找其相邻节点的描述符,最后(c)引用每个相邻节点的描述符通过它们各自的描述符。
所有这些记账的最终结果显然是需要其他容器(例如
std::map
)以提供从顶点和边缘(同样,类型VertexProperty
和EdgeProperty
)到其描述符的反向查找。 我在a similar SO question中发现了此声明,但无法在任何地方的Boost docs中进行验证。在随后的讨论中,我不得不推测约束实际上可能更强一些:“BGL并不意味着直接引用堆。”但是,这似乎并不完全合理,因为容器类型是可配置的(上面的
OutEdgeList
和VertexList
)和默认的标准对象(例如 vector )。 我是BGL n00b,无法理解 bundle 属性的用途。 (坦率地说,我对编程模型总的来说有点不知所措-“属性”,“概念”,“特征”,“描述符”,AHHHH!)
VertexProperty
和EdgeProperty
的复杂且可能是堆绑定(bind)的类型?还是说这些是轻量级的存储不变数据的容器? 最佳答案
当然。您可以随时执行此操作。以防万一:您可以使 bundle 包持有(不可更改或可变的)指针指向分配给“复杂”类型的堆的指针,该指针当然是完全可变的。现在,
我建议您使用首选的所有权适配器(unique_ptr,scoped_ptr,shared_ptr等)。看一下std::string
:它也是基于“堆”的,但是您从来没有担心过在属性包中使用它,是吗?
严格地没有任何“描述符簿记”。可能取决于图模型。但总的来说,描述符实际上是底层容器迭代器模型的抽象(并不是说它可以是跨多个容器的迭代器,例如edges(EdgeListgraph)
而不是out_edges(v, IncidenceGraph)
的adjacency_list<>
。
关键是要使逻辑与关于存储模型的假设脱钩。即使传递了一些难看的void*
,编译器也应将其编译为与直接迭代器访问相同的代码。从这个意义上说,“簿记”通常是感知性的,您可能会承担额外概念层的 spirit 负担。
哎呀。我认为我不小心在1下解决了这个问题。使用绝对绝对最简单的方法可能是重新共享。您的具体情况可能允许使用更有效的解决方案。
卡皮塔精选
好吧,也许不是 bundle 销售。即使在这里,也仅取决于您如何管理指针的所有权/生存期。
我认为链接的答案非常好。这与我上面所说的一致。
大多数BGL算法都依靠vertex_index_t
属性的存在(或要求将其指定为参数)来确保它们是低成本的操作。实际上,如果使用vecS
,则顶点索引就是顶点 vector 的索引,因此反向和正向查找非常简单。 (您始终可以查看启用了优化的生成的程序集,以查看是否有任何意外)。
这个答案可能是鼓舞人心的:Boost Graph Library: possible to combine Bundled Properties with Interior Properties?
TL; DR/摘要
我有一种来自Python的感觉,您可能会低估了模板密集型通用库代码中的C++优化编译器,这是可以理解的。
当您在实践中遍历通用机械层时,冒出的气泡在编译时蒸发。当然,这样做的缺点是很难通过抽象来理解。但这也意味着功能和抽象级别不会受到损害。
BGL是一个库,它使您只需很少的代码更改即可切换到完全不同的图形模型,存储布局等。这里的目标不是“易于使用”或“按我的意思”(为此使用Java或python)。
目标是通过将每个实现细节硬编码到整个代码库中,从而选择C++/not/消除所有敏捷性。相反,您可以在库概念级别上工作,并受益于您保留的自由,可以随需求的发展进行实验/更改方法。