如何复制包含图本身的boost图的顶点属性?

问题描述 投票:0回答:1

我有一个带有自定义属性的增强图。我想复印一份。我按照以下方法尝试过。

using BGType = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS,
                                     // Vertex Properties...
                                     vertexProps,
                                     // Edge Propereties...
                                     edgeProps,
                                     // Graph Properties
                                     graphProps>;

vertexProps.h

class vertexProps {
   public:
    explicit vertexProps(const std::string *moduleName = nullptr, const std::string *name = nullptr,
                            long refPtr = 0 )
     : _refPtr(refPtr),
    {
        _moduleName = moduleName ? *moduleName : "";
        _name = name ? *name : "";
    };
   std::string _moduleName;
   std::string _name;
   BGType *_subGraph = nullptr;
   BGType *_graph = nullptr;
struct CustomVertexCopy {
    BGType const &g1;
    BGType &g2;
    void operator()(BGType::vertex_descriptor v1, BGType::vertex_descriptor v2) const
    {
        schVertexProps const &p1 = g1[v1];
        schVertexProps &p2 = g2[v2];
        p2._subGraph = p1._subGraph;
        p2._graph = p1._graph;
        p2._moduleName = p1._moduleName;
        p2._name = p1._name;
    }
};

edgeProps.h

class edgeProps {
   public:
    explicit edgeProps(std::string name = "")
        : _name(name){};
    std::string _name;
};

struct CustomEdgeCopy {
    BGType const &g1;
    BGType &g2;

    void operator()(BGType::edge_descriptor e1, BGType::edge_descriptor e2) const { g2[e2]._name = g1[e1]._name; }
};

一些函数.cpp

OnClick(BGType* bgNew)
{
   // some code
  BGType* oldBg = new BGType;
  boost::copy_graph(
                  *bgNew, *oldBg,
                  boost::vertex_copy(CustomVertexCopy{*bgNew, *oldBg}).edge_copy(CustomEdgeCopy{*bgNew, *oldBg}));
  boost::get_property(*oldBg) = boost::get_property(*bgNew);
  // Copying graph properties
  DeepCopyOfBG(bgNew, oldBg);
}

void someFunction::DeepCopyOfBG(BGType* bGraph, BGType* oldBg)
{
    // Iterate through the source map and copy its contents
    for (const auto& entry : (*bGraph)[boost::graph_bundle]._modInfo) {
        const std::string& key = entry.first;
        const auto& value = entry.second;

        // Create a deep copy of value (a tuple containing vectors of schPinInfo)
        std::tuple<std::vector<schPinInfo*>, std::vector<schPinInfo*>, std::vector<schPinInfo*>> deepCopyValue = value;

        // Add the deep copy to the target map
        (*oldBg)[boost::graph_bundle]._modInfo[key] = deepCopyValue;
    }
    // some more properties.
}

以上方法工作正常。但它有 1 个问题。 Vertex 属性有 1 个字段,它本身就是一个 boost 图。

p2._subGraph = p1._subGraph;

上面的行只是复制指针。因此,在旧的升压图中,我得到了我不想要的新升压图的子图。 那么如何深度复制这个_subGraph字段呢?

c++ c++11 boost-graph
1个回答
0
投票

Vertex 属性有 1 个字段,它本身就是一个 boost 图

确实没有。正如您自己指出的,它包含指向图形的指针。这根本不是一回事。

上面的行只是复制指针。因此,在旧的升压图中,我得到了我不想要的新升压图的子图。那么如何深度复制这个_subGraph字段呢?

我怀疑你确实想要它,因为复制每个顶点的图是昂贵的。因此,除非您使用小图,否则我建议使用 shared_ptr<BGType const>

 来接受间接寻址,这也解决了生命周期问题(您的代码几乎不可避免地会像现在一样遭受内存泄漏)。

旁注:

p2._graph = p1._graph;
看起来也很可疑。应该是

p2._graph = &g2;

吗?

解决方案1

如果您想要完整副本,最简单的方法是不使用指针,因此该行

p2._subGraph = p1._subGraph;
实际上复制了对象。

解决方案2

您显然可以将其拼写出来,通过使用原始指针引入新的内存泄漏机会:

p2._subGraph = new BTType(*p1._subGraph);
由于您仍在执行复杂的舞蹈来复制其他位置的图表,因此您可能需要在此处重复该操作。我建议创建一个函数来完成它:

p2._subGraph = my_graph_copy_function(p1._subGraph);
演示

我将按照惯例提供一个演示,但我将基于我的

之前的建议来展示完整的价值语义,从而避免首先复制图表带来的所有不必要的复杂情况。

现在,因为这里存在递归(图的节点包含图,图的节点包含......等),我们必须使用某种动态分配。我选择了一个“value_ptr”,它基本上是一个通过深拷贝复制的

unique_ptr

struct BGType; // forward using SubGraph = value_ptr<BGType>; struct vertexProps { std::string _moduleName; std::string _name; long _refPtr; SubGraph _subGraph; };
现在默认的副本分配将执行您想要的操作,没有内存泄漏的风险,并且无需编写过于复杂的代码。

因为

BGType

需要在这里向前声明,所以我们必须将其定义为一个结构体 - 我们可以通过继承来做到这一点:

struct BGType : BGTypeImpl { using BGTypeImpl::BGTypeImpl; using BGTypeImpl::operator=; };
现在主要是:

int main() { BGType g1 = make_graph(); BGType g2; g2 = g1; // FULL COPY std::cout << "g2:\n" << g2 << "\n"; std::cout << "address of subgraph in g1: " << g1[2]._subGraph.address() << "\n"; std::cout << "address of subgraph in g2: " << g2[2]._subGraph.address() << "\n"; }
我们可以

得到输出

g2: digraph G { label=name; 0 [moduleName=Hello, name=world, ref=111, subGraph="(none)"]; 1 [moduleName=Goodbye, name=moon, ref=222, subGraph="(none)"]; 2 [moduleName=Greetings, name=Cosmos, ref=333, subGraph="digraph G { label=sub; 0 [moduleName=Greetings, name=Cosmos, ref=333, subGraph=\"(none)\"]; 1 [moduleName=\"\", name=\"\", ref=0, subGraph=\"(none)\"]; 0->0 [name=nested]; } "]; 0->1 [name=one]; 2->0 [name=two]; } address of subgraph in g1: 0x1025900 address of subgraph in g2: 0x1025ba0
请注意,子图地址是不同的。这里没有内存泄漏。

完整列表

住在Coliru

#include <boost/graph/adjacency_list.hpp> #include <boost/graph/graphviz.hpp> // forward declarations so we can have recursive object structure template <typename T> struct value_ptr { /*explicit*/ value_ptr(std::nullptr_t = {}) {} /*explicit*/ value_ptr(T v) : p_(std::make_unique<T>(std::move(v))) {} value_ptr(value_ptr const& rhs) : p_(rhs.p_ ? std::make_unique<T>(*rhs.p_) : nullptr) {} value_ptr& operator=(value_ptr const& rhs) { p_ = rhs.p_ ? std::make_unique<T>(*rhs.p_) : nullptr; return *this; } value_ptr(value_ptr&& rhs) = default; value_ptr& operator=(value_ptr&& rhs) = default; explicit operator bool() const { return !!p_; } auto& operator*() const { return *p_; } auto& operator->() const { return *p_; } auto address() const { return p_.get(); } private: std::unique_ptr<T> p_; friend std::ostream& operator<<(std::ostream& os, value_ptr const& p) { if (!p) return os << "(none)"; return os << *p; } friend std::istream& operator>>(std::istream& is, value_ptr&) { // dynamic properties cannot be readonly is.setstate(std::ios::failbit); return is; } }; struct BGType; // forward using SubGraph = value_ptr<BGType>; struct vertexProps { std::string _moduleName; std::string _name; long _refPtr = 0; SubGraph _subGraph; }; struct edgeProps { edgeProps(edgeProps const&) = default; edgeProps& operator=(edgeProps const&) = default; explicit edgeProps(std::string name = "") : _name(name){}; std::string _name; }; struct schPinInfo { std::string id; }; schPinInfo const wellknownPins[] = { {"i1"}, {"i2"}, {"i3"}, {"o4"}, {"o5"}, {"i6"}, {"i7"}, {"i8"}, {"o9"}, {"o10"}, }; static schPinInfo const* const i1 = wellknownPins + 0; static schPinInfo const* const i2 = wellknownPins + 1; static schPinInfo const* const i3 = wellknownPins + 2; static schPinInfo const* const o4 = wellknownPins + 3; static schPinInfo const* const o5 = wellknownPins + 4; static schPinInfo const* const i6 = wellknownPins + 5; static schPinInfo const* const i7 = wellknownPins + 6; static schPinInfo const* const i8 = wellknownPins + 7; static schPinInfo const* const o9 = wellknownPins + 8; static schPinInfo const* const o10 = wellknownPins + 9; using Pins = std::vector<schPinInfo const*>; struct Layout { Pins input, inout, output; }; struct schSymbol {}; struct graphProps { graphProps& operator=(graphProps const&) = default; explicit graphProps(std::string name = {}) : _name(std::move(name)) {} std::string _name; std::map<std::string, Layout> _modInfo; std::map<std::string, std::vector<std::string>> _altNames; std::map<std::string, schSymbol> _modSymbol; }; using BGTypeImpl = boost::adjacency_list< // boost::vecS, boost::vecS, boost::bidirectionalS, // vertexProps, edgeProps, graphProps>; struct BGType : BGTypeImpl { using BGTypeImpl::BGTypeImpl; using BGTypeImpl::operator=; friend auto& get_property(BGType& g, boost::graph_bundle_t prop) { return boost::get_property(static_cast<BGTypeImpl&>(g), prop); } friend auto& get_property(BGType const& g, boost::graph_bundle_t prop) { return boost::get_property(static_cast<BGTypeImpl const&>(g), prop); } friend std::ostream& operator<<(std::ostream& os, BGType const& g) { boost::dynamic_properties dp; // this is ugly, but see https://stackoverflow.com/a/27238425/85371 auto& ncg = const_cast<BGType&>(g); dp.property("node_id", get (boost::vertex_index, g)); dp.property("moduleName", get (&vertexProps::_moduleName, ncg)); dp.property("name", get (&vertexProps::_name, ncg)); dp.property("subGraph", get (&vertexProps::_subGraph, ncg)); dp.property("ref", get (&vertexProps::_refPtr, ncg)); dp.property("name", get (&edgeProps::_name, ncg)); dp.property("label", boost::make_constant_property<BGType*>(get_property(g)._name)); write_graphviz_dp(os, g, dp); return os; } }; // implement functions now that BGType is complete BGType make_graph() { BGType g{3, graphProps{"name"}}; boost::get_property(g)._modInfo = { {"mod1", Layout{{i1, i2, i3}, {}, {o4, o5}}}, {"mod2", Layout{{i6, i7, i8}, {}, {o9, o10}}}, }; boost::get_property(g)._altNames = { {"mod1", {"MOD1", "MOD_1"}}, {"mod2", {"MOD2", "MOD_2"}}, }; boost::get_property(g)._modSymbol = { {"mod1", schSymbol{}}, {"mod2", schSymbol{}}, }; g[0] = vertexProps{"Hello", "world", 111, {}}; g[1] = vertexProps{"Goodbye", "moon", 222, {}}; g[2] = vertexProps{"Greetings", "Cosmos", 333, {}}; { // add a subgraph to vertex 2 BGType sub(2, graphProps{"sub"}); sub[0] = vertexProps{"Greetings", "Cosmos", 333, {}}; add_edge(0, 0, edgeProps{"nested"}, sub); g[2]._subGraph = sub; } add_edge(0, 1, edgeProps{"one"}, g); add_edge(2, 0, edgeProps{"two"}, g); return g; } int main() { BGType g1 = make_graph(); BGType g2; g2 = g1; // FULL COPY std::cout << "g2:\n" << g2 << "\n"; std::cout << "address of subgraph in g1: " << g1[2]._subGraph.address() << "\n"; std::cout << "address of subgraph in g2: " << g2[2]._subGraph.address() << "\n"; }
    
© www.soinside.com 2019 - 2024. All rights reserved.