我有一个带有自定义属性的增强图。我想复印一份。我按照以下方法尝试过。
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字段呢?
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
请注意,子图地址是不同的。这里没有内存泄漏。完整列表
#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";
}