如何在大小为 int64_t 的 Boost 图中使用顶点标识符
How to use vertex dentifiers in Boost graph of size int64_t
我正在尝试使用 boost::add_edge(...) 向 Boost 无向图添加边。该图定义为:
using osm_id_t = int64_t;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
// vertex properties
boost::property<boost::vertex_index_t, osm_id_t,
boost::property<boost::vertex_color_t, boost::default_color_type> >,
// edge properties
boost::no_property> UndirectedOSMIdGraph;
我没有遇到编译错误。如果顶点是整数(例如 boost::add_edge(1, 2, g)),我的代码工作正常。但是,一旦我将顶点添加为 int64_t,我就会得到一个“在抛出 'std::bad_alloc'
实例后调用的终止
UndirectedOSMIdGraph g;
osm_id_t large {1810014749};
boost::add_edge (large, 2, g); //if instead large is just 1 it works
boost::add_edge (2, 3, g);
...
我想我必须以某种方式指定顶点数的大小 - 但我只是不知道该怎么做。注意:我不想向顶点添加额外的属性 - 我只需要大量的顶点(因为它们是来自 OpenStreetMap 的标识符)。
使用vecS
顶点索引是隐式的。它们对应于顶点存储容器中的索引,即vector。
这意味着如果顶点数少于 1810014750,则在 g
上使用顶点索引 1810014749 将是未定义的行为。 “幸运的是”(?)对你来说 add_edge
足够聪明,可以检测到这一点并在 vecS
容器选择器的情况下调整向量的大小,因此它会尝试为添加之前提到的最高顶点 ID 分配足够的存储空间边缘,失败是因为您的程序无法访问那么多内存:
at /usr/include/c++/10/ext/new_allocator.h:115
115 return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
此处,1810014750 * sizeof(_Tp)
为 14,48 GB。
除此之外,64 位没有问题,因为顶点描述符已经是 64(尽管未签名):
using V = UndirectedOSMIdGraph::vertex_descriptor;
static_assert(not std::is_same_v<osm_id_t, V>);
static_assert(std::is_same_v<std::make_unsigned_t<osm_id_t>, V>);
static_assert(sizeof(osm_id_t) == sizeof(V));
因此,只要您实际上不使用负数 osm_id_t
,使用 osm_id_t
作为索引就没有 技术 障碍。
“稀疏”顶点索引
如果您的顶点索引不密集,那么 vecS
可能不太适合您的存储。考虑使用其他东西:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
using osm_id_t = int64_t;
using UndirectedOSMIdGraph = boost::adjacency_list<
boost::vecS, boost::listS, boost::undirectedS,
boost::property<
boost::vertex_index_t, osm_id_t,
boost::property<boost::vertex_color_t, boost::default_color_type>>,
boost::no_property>;
using V = UndirectedOSMIdGraph::vertex_descriptor;
static_assert(not std::is_same_v<std::make_unsigned_t<osm_id_t>, V>);
int main() {
UndirectedOSMIdGraph g;
osm_id_t large{1810014749};
auto v2 = add_vertex(2, g);
add_edge(add_vertex(large, g), v2, g);
add_edge(v2, add_vertex(3, g), g);
print_graph(g);
}
版画
2 <--> 1810014749 3
1810014749 <--> 2
3 <--> 2
我正在尝试使用 boost::add_edge(...) 向 Boost 无向图添加边。该图定义为:
using osm_id_t = int64_t;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
// vertex properties
boost::property<boost::vertex_index_t, osm_id_t,
boost::property<boost::vertex_color_t, boost::default_color_type> >,
// edge properties
boost::no_property> UndirectedOSMIdGraph;
我没有遇到编译错误。如果顶点是整数(例如 boost::add_edge(1, 2, g)),我的代码工作正常。但是,一旦我将顶点添加为 int64_t,我就会得到一个“在抛出 'std::bad_alloc'
实例后调用的终止 UndirectedOSMIdGraph g;
osm_id_t large {1810014749};
boost::add_edge (large, 2, g); //if instead large is just 1 it works
boost::add_edge (2, 3, g);
...
我想我必须以某种方式指定顶点数的大小 - 但我只是不知道该怎么做。注意:我不想向顶点添加额外的属性 - 我只需要大量的顶点(因为它们是来自 OpenStreetMap 的标识符)。
使用vecS
顶点索引是隐式的。它们对应于顶点存储容器中的索引,即vector。
这意味着如果顶点数少于 1810014750,则在 g
上使用顶点索引 1810014749 将是未定义的行为。 “幸运的是”(?)对你来说 add_edge
足够聪明,可以检测到这一点并在 vecS
容器选择器的情况下调整向量的大小,因此它会尝试为添加之前提到的最高顶点 ID 分配足够的存储空间边缘,失败是因为您的程序无法访问那么多内存:
at /usr/include/c++/10/ext/new_allocator.h:115
115 return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
此处,1810014750 * sizeof(_Tp)
为 14,48 GB。
除此之外,64 位没有问题,因为顶点描述符已经是 64(尽管未签名):
using V = UndirectedOSMIdGraph::vertex_descriptor;
static_assert(not std::is_same_v<osm_id_t, V>);
static_assert(std::is_same_v<std::make_unsigned_t<osm_id_t>, V>);
static_assert(sizeof(osm_id_t) == sizeof(V));
因此,只要您实际上不使用负数 osm_id_t
,使用 osm_id_t
作为索引就没有 技术 障碍。
“稀疏”顶点索引
如果您的顶点索引不密集,那么 vecS
可能不太适合您的存储。考虑使用其他东西:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
using osm_id_t = int64_t;
using UndirectedOSMIdGraph = boost::adjacency_list<
boost::vecS, boost::listS, boost::undirectedS,
boost::property<
boost::vertex_index_t, osm_id_t,
boost::property<boost::vertex_color_t, boost::default_color_type>>,
boost::no_property>;
using V = UndirectedOSMIdGraph::vertex_descriptor;
static_assert(not std::is_same_v<std::make_unsigned_t<osm_id_t>, V>);
int main() {
UndirectedOSMIdGraph g;
osm_id_t large{1810014749};
auto v2 = add_vertex(2, g);
add_edge(add_vertex(large, g), v2, g);
add_edge(v2, add_vertex(3, g), g);
print_graph(g);
}
版画
2 <--> 1810014749 3
1810014749 <--> 2
3 <--> 2