c++ - 使用 std::unique_ptr 提升图捆绑属性
问题描述
此答案显示 astd::unique_ptr
作为带有 boost-graph 的捆绑属性的成员。
提供的示例可以试用 Live On Coliru。
由于我只对设计方面感兴趣,而不是该答案的算法部分,因此我提供了一个简化的示例Live On Coliru。
#include <iostream>
#include <fstream>
#include <boost/graph/adjacency_list.hpp>
struct custom_node{
custom_node(std::string name, int capacity) : name(name), capacity(capacity) {}
std::string name = "uninitialized";
int capacity = -1;
};
void usage(){}
using namespace boost;
struct VertexProperties {
int id;
std::unique_ptr<custom_node> node;
};
typedef adjacency_list<vecS, vecS, directedS, VertexProperties> DirectedGraph;
typedef graph_traits<DirectedGraph>::vertex_descriptor custom_vertex;
typedef graph_traits<DirectedGraph>::edge_descriptor custom_edge;
int main() {
DirectedGraph g;
boost::add_vertex(g);
g[0].node = std::make_unique<custom_node>("inner", 2);
////boost::add_vertex(VertexProperties{0, std::make_unique<custom_node>("inner", 2)}, g); // compilation error
std::cout << boost::num_vertices(g);
std::cout << g[0].id << "\n";
std::cout << g[0].node->name << "\n";
std::cout << g[0].node->capacity << "\n";
}
顶点可以通过添加boost::add_vertex(g)
,然后std::unique_ptr
可以实例化。
如果我尝试通过在 中通过列表初始化创建具有所有属性的顶点来实现相同的目的add_vertex
,则会出现关于implicitly-deleted copy constructor of 'VertexProperties'
.
VertexProperties
,当然,它的复制构造函数被删除了,因为std::unique_ptr
它的复制构造函数被删除了。
为什么列表初始化首先需要复制构造函数?有什么我不明白的地方,还是boost-graph的缺点?
解决方案
为什么列表初始化首先需要复制构造函数?有什么我不明白的地方,还是boost-graph的缺点?
这不是一件事,也不是正在发生的事情。
另外:在复制初始化中,编译器可以省略赋值,但 operator= 仍然需要可访问才能使其成为有效代码。
但在这种情况下,只是库代码没有移动感知。您必须意识到“捆绑”属性是单独存储的。捆绑包(作为任何属性)无论如何都必须是默认可构造的(因此add_vertex(g)
有效),因此通过始终分配给默认构造的属性来简化实现。
由于它不是移动感知的,因此分配不会转发右值并且事情不会编译。
选项
链接的答案已经显示:
if(g[v].node_logic) { g[v].node.reset(new custom_node(g[v].vertex_name, 0, standby, normal)); }
更多选择:
VertexProperties props {0, std::make_unique<custom_node>("inner", 2)}; auto vd = boost::add_vertex(g); g[vd] = std::move(props);
包裹你的狗屎!您可以创建任何您喜欢的界面:
auto add_vertex = [&g](VertexProperties&& props) { auto vd = boost::add_vertex(g); g[vd] = std::move(props); return vd; }; add_vertex({0, std::make_unique<custom_node>("inner", 2)});
你甚至可以详细说明:
auto add_vertex = [&g](int id, std::string name, int capacity = -1) { auto vd = boost::add_vertex(g); g[vd] = { id, std::make_unique<custom_node>(name, capacity) }; return vd; }; add_vertex(0, "inner", 2); add_vertex(1, "outer", 3); add_vertex(2, "other");
以上所有选项Live On Coliru
无论如何,如果你问我,后者的界面要好得多。
如果您愿意,可以使用 ADL 将其提供给其他人:
#include <boost/graph/adjacency_list.hpp>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <memory>
namespace MyLib { // for ADL demo
struct custom_node {
custom_node(std::string name, int capacity)
: name(std::move(name)), capacity(capacity) {}
std::string name = "uninitialized";
int capacity = -1;
friend std::ostream& operator<<(std::ostream& os, custom_node const& cn) {
return os << "{" << std::quoted(cn.name) << ", " << cn.capacity << "}";
}
};
struct VertexProperties {
int id{};
std::unique_ptr<custom_node> node;
friend std::ostream& operator<<(std::ostream& os, VertexProperties const& vp) {
os << vp.id;
if (vp.node)
os << ", " << *vp.node;
return os;
}
};
template <typename G>
auto add_vertex(G& g, int id, const std::string& name, int capacity = -1) {
auto vd = boost::add_vertex(g);
g[vd] = { id, std::make_unique<custom_node>(name, capacity) };
return vd;
}
}
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, MyLib::VertexProperties>;
using custom_vertex = Graph::vertex_descriptor;
using custom_edge = Graph::edge_descriptor;
int main() {
Graph g;
add_vertex(g, 10, "inner", 2);
add_vertex(g, 11, "outer", 3);
add_vertex(g, 12, "other");
for (auto vd : boost::make_iterator_range(vertices(g))) {
std::cout << g[vd] << "\n";
}
}
印刷
10, {"inner", 2}
11, {"outer", 3}
12, {"other", -1}
有人提到设计?
如果您想要的只是具有可选/惰性构造的唯一所有权,为什么不:
struct VertexProperties {
int id{};
std::optional<custom_node> node;
};
甚至只是
struct VertexProperties {
int id{};
custom_node node;
};
所有权语义将是相同的,没有成本:
Graph g;
add_vertex({10, custom_node{"inner", 2}}, g);
add_vertex({11, custom_node{"outer", 3}}, g);
add_vertex({12, custom_node{"other"}}, g);
这只是使用boost::add_vertex
BGL 的标准重载。没有optional<>
它会变得更简单:
add_vertex({10, {"inner", 2}}, g);
add_vertex({11, {"outer", 3}}, g);
add_vertex({12, {"other"}}, g);
也Live On Coliru(没有 std::optional: Live)
#include <boost/graph/adjacency_list.hpp>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <memory>
#include <optional>
struct custom_node {
custom_node(std::string name, int capacity = -1)
: name(std::move(name)), capacity(capacity) {}
std::string name = "uninitialized";
int capacity = -1;
friend std::ostream& operator<<(std::ostream& os, custom_node const& cn) {
return os << "{" << std::quoted(cn.name) << ", " << cn.capacity << "}";
}
};
struct VertexProperties {
int id{};
std::optional<custom_node> node;
friend std::ostream& operator<<(std::ostream& os, VertexProperties const& vp) {
os << vp.id;
if (vp.node) os << ", " << *vp.node;
return os;
}
};
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexProperties>;
using custom_vertex = Graph::vertex_descriptor;
using custom_edge = Graph::edge_descriptor;
int main() {
Graph g;
add_vertex({10, custom_node{"inner", 2}}, g);
add_vertex({11, custom_node{"outer", 3}}, g);
add_vertex({12, custom_node{"other"}}, g);
for (auto vd : boost::make_iterator_range(vertices(g))) {
std::cout << g[vd] << "\n";
}
}
印刷
10, {"inner", 2}
11, {"outer", 3}
12, {"other", -1}
推荐阅读
- tensorflow - 您能否澄清分类问题中“一次性编码标签以使用 MSE”背后的逻辑
- php - Symfony CLI 在运行“new”命令时没有使用正确的 PHP 版本
- reactjs - 在 React Bootstrap 中换行列内容
- python - 日期和时间 - 设置为 telnet 连接
- java - 使用多种类型的通用项目进行映射以获得价值
- flutter - Flutter Widget Test expansionTile 未在 tester.tap() 上打开
- elasticsearch - ElasticSearch 不返回任何结果
- slurm - slurm 的 #SBATCH 指令中的 bash 变量扩展
- git - Git PR 只显示提交,不显示文件
- arrays - 特殊字符串与数组元素 BASH 比较