我有一个带有顶点、边和图属性的增强图。我想复制一份 boost braph。我将一个增强图的顶点和边属性(使用
copy_graph
)复制到另一个增强图中,但无法复制图属性。
using BGType = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS,
// Vertex Properties...
vertexProps,
// Edge Propereties...
edgeProps,
// Graph Properties
graphProps>;
我有图形属性:
class graphProps {
public:
explicit graphProps(std::string *name = nullptr) { _name = name ? *name : ""; };
std::string _name;
std::map<std::string, std::tuple<std::vector<schPinInfo *>, // input Pins
std::vector<schPinInfo *>, // inout pins
std::vector<schPinInfo *>> // output pins
>
_modInfo;
std::map<std::string, std::vector<std::string>> _altNames;
std::map<std::string, schSymbol> _modSymbol;
}
struct CustomVertexCopy {
BGType const& g1;
BGType& g2;
void operator()(BGType::vertex_descriptor v1, BGType::vertex_descriptor v2) const {
vertexProps const& p1 = g1[v1];
vertexProps& p2 = g2[v2];
p2._refPtr = p1._refPtr;
p2._moduleName = p1._moduleName;
p2._name = p1._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;
}
};
我的copy_graph是这样的:
OnClick(BGType* bGraph)
{
// some code
BGType* oldBg = new BGType;
boost::copy_graph(*bGraph, *oldBg,
boost::vertex_copy(CustomVertexCopy{*bGraph,*oldBg})
.edge_copy(CustomEdgeCopy{*bGraph, *oldBg}));
// some code
}
如何复制图表属性?
简单来说
boost::copy_graph
不支持。
只需复制分配就可以了:
boost::get_property(g2) = boost::get_property(g1)
改编自您之前的演示问题:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <fmt/ranges.h>
class vertexProps {
public:
vertexProps(vertexProps const&) = default;
vertexProps& operator=(vertexProps const&) = default;
explicit vertexProps(std::string mn = {}, std::string n = {}, long refPtr = 0)
: _moduleName(std::move(mn))
, _name(std::move(n))
, _refPtr(refPtr) {}
std::string _moduleName;
std::string _name;
long _refPtr;
};
class edgeProps {
public:
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 BGType = boost::adjacency_list< //
boost::vecS, boost::vecS, boost::bidirectionalS, //
vertexProps, edgeProps, graphProps>;
int main() {
BGType g2;
{
BGType g1{3, graphProps{"name"}};
{
boost::get_property(g1)._modInfo = {
{"mod1", Layout{{i1, i2, i3}, {}, {o4, o5}}},
{"mod2", Layout{{i6, i7, i8}, {}, {o9, o10}}},
};
boost::get_property(g1)._altNames = {
{"mod1", {"MOD1", "MOD_1"}},
{"mod2", {"MOD2", "MOD_2"}},
};
boost::get_property(g1)._modSymbol = {
{"mod1", schSymbol{}},
{"mod2", schSymbol{}},
};
g1[0] = vertexProps{"Hello", "world", 111};
g1[1] = vertexProps{"Goodbye", "moon", 222};
g1[2] = vertexProps{"Greetings", "Cosmos", 333};
add_edge(0, 1, edgeProps{"one"}, g1);
add_edge(2, 0, edgeProps{"two"}, g1);
}
g2 = g1; // FULL COPY
// copy_graph(g1, g2); // doesn't copy graph property
}
boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, g2));
dp.property("moduleName", get(&vertexProps::_moduleName, g2));
dp.property("name", get(&vertexProps::_name, g2));
dp.property("ref", get(&vertexProps::_refPtr, g2));
dp.property("name", get(&edgeProps::_name, g2));
dp.property("name", get(&edgeProps::_name, g2));
write_graphviz_dp(std::cout, g2, dp);
fmt::print("Copied _altNames: {}\n", boost::get_property(g2)._altNames);
}
打印
digraph G {
0 [moduleName=Hello, name=world, ref=111];
1 [moduleName=Goodbye, name=moon, ref=222];
2 [moduleName=Greetings, name=Cosmos, ref=333];
0->1 [name=one, name=one];
2->0 [name=two, name=two];
}
Copied _altNames: {"mod1": ["MOD1", "MOD_1"], "mod2": ["MOD2", "MOD_2"]}
如果您希望
schPinInfo
对象也被深度复制怎么办?为了正确进行对象跟踪,以便重复的引脚不会被多次序列化(反序列化),我建议使用 Boost Serialization:
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/graph/adj_list_serialize.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <fmt/ranges.h>
class vertexProps {
public:
vertexProps(vertexProps const&) = default;
vertexProps& operator=(vertexProps const&) = default;
explicit vertexProps(std::string mn = {}, std::string n = {}, long refPtr = 0)
: _moduleName(std::move(mn))
, _name(std::move(n))
, _refPtr(refPtr) {}
std::string _moduleName;
std::string _name;
long _refPtr;
};
class edgeProps {
public:
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 BGType = boost::adjacency_list< //
boost::vecS, boost::vecS, boost::bidirectionalS, //
vertexProps, edgeProps, graphProps>;
void serialize(auto& ar, vertexProps& p, unsigned) { ar& p._moduleName& p._name& p._refPtr; }
void serialize(auto& ar, edgeProps& p, unsigned) { ar& p._name; }
void serialize(auto& ar, graphProps& p, unsigned) { ar& p._name& p._modInfo& p._altNames& p._modSymbol; }
void serialize(auto&, schSymbol&, unsigned) { }
void serialize(auto& ar, schPinInfo& i, unsigned) { ar& i.id; }
void serialize(auto& ar, Layout& l, unsigned) { ar& l.input& l.inout& l.output; }
BGType deep_copy(BGType const& g1) {
std::stringstream ss;
boost::archive::binary_oarchive(ss) << g1;
BGType g2;
boost::archive::binary_iarchive(ss) >> g2;
return g2;
}
int main() {
BGType g2;
{
BGType g1{3, graphProps{"name"}};
{
boost::get_property(g1)._modInfo = {
{"mod1", Layout{{i1, i2, i3}, {}, {o4, o5}}},
{"mod2", Layout{{i6, i7, i8}, {}, {o9, o10}}},
};
boost::get_property(g1)._altNames = {
{"mod1", {"MOD1", "MOD_1"}},
{"mod2", {"MOD2", "MOD_2"}},
};
boost::get_property(g1)._modSymbol = {
{"mod1", schSymbol{}},
{"mod2", schSymbol{}},
};
g1[0] = vertexProps{"Hello", "world", 111};
g1[1] = vertexProps{"Goodbye", "moon", 222};
g1[2] = vertexProps{"Greetings", "Cosmos", 333};
add_edge(0, 1, edgeProps{"one"}, g1);
add_edge(2, 0, edgeProps{"two"}, g1);
assert(boost::get_property(g1)._modInfo["mod2"].input.at(0) == i6);
assert(boost::get_property(g1)._modInfo["mod2"].input.at(1) == i7);
assert(boost::get_property(g1)._modInfo["mod2"].input.at(2) == i8);
assert(boost::get_property(g1)._modInfo["mod2"].output.at(0) == o9);
assert(boost::get_property(g1)._modInfo["mod2"].output.at(1) == o10);
}
g2 = deep_copy(g1); // even deeply copied schPinInfo const* objects!
assert(boost::get_property(g2)._modInfo["mod2"].input.at(0) != i6);
assert(boost::get_property(g2)._modInfo["mod2"].input.at(1) != i7);
assert(boost::get_property(g2)._modInfo["mod2"].input.at(2) != i8);
assert(boost::get_property(g2)._modInfo["mod2"].output.at(0) != o9);
assert(boost::get_property(g2)._modInfo["mod2"].output.at(1) != o10);
}
boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, g2));
dp.property("moduleName", get(&vertexProps::_moduleName, g2));
dp.property("name", get(&vertexProps::_name, g2));
dp.property("ref", get(&vertexProps::_refPtr, g2));
dp.property("name", get(&edgeProps::_name, g2));
dp.property("name", get(&edgeProps::_name, g2));
write_graphviz_dp(std::cout, g2, dp);
fmt::print("Copied _altNames: {}\n", boost::get_property(g2)._altNames);
// note the deeply allocated schPinInfo are leaked!
}
印刷
digraph G {
0 [moduleName=Hello, name=world, ref=111];
1 [moduleName=Goodbye, name=moon, ref=222];
2 [moduleName=Greetings, name=Cosmos, ref=333];
0->1 [name=one, name=one];
2->0 [name=two, name=two];
}
Copied _altNames: {"mod1": ["MOD1", "MOD_1"], "mod2": ["MOD2", "MOD_2"]}
备注:
断言全部通过 - 使深度克隆
schPinInfo
变得有形。
schPinInfo
的反序列化实例现已泄漏,这就是为什么您不应该使用原始指针:
==794912==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 320 byte(s) in 10 object(s) allocated from:
#0 0x7f11ffec21e7 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
#1 0x55698a066997 in boost::archive::detail::heap_allocation<schPinInfo>::doesnt_have_new_operator::invoke_new() /home/sehe/custom/superboost/boost/archive/detail/iserializer.hpp:243
#2 0x55698a066997 in boost::archive::detail::heap_allocation<schPinInfo>::invoke_new() /home/sehe/custom/superboost/boost/archive/detail/iserializer.hpp:257
#3 0x55698a066997 in boost::archive::detail::heap_allocation<schPinInfo>::heap_allocation() /home/sehe/custom/superboost/boost/archive/detail/iserializer.hpp:270
#4 0x55698a066997 in boost::archive::detail::pointer_iserializer<boost::archive::binary_iarchive, schPinInfo>::heap_allocation() const /home/sehe/custom/superboost/boost/archive/detail/iserializer.hpp:295
SUMMARY: AddressSanitizer: 320 byte(s) leaked in 10 allocation(s).