Skip to content

Commit aeabf1e

Browse files
committed
static assert to prevent remove_vertex with vecS label storage that would invalidate all label-to-vertex mappings after the erased position
1 parent 54108e8 commit aeabf1e

4 files changed

Lines changed: 59 additions & 10 deletions

File tree

include/boost/graph/labeled_graph.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,13 @@ class labeled_graph : protected labeled_graph_types< Graph, Label, Selector >
501501
/** Remove the vertex with the given label. */
502502
void remove_vertex(Label const& l)
503503
{
504+
static_assert(
505+
!is_same<
506+
typename graph_detail::container_traits<map_type>::category,
507+
graph_detail::vector_tag
508+
>::value,
509+
"remove_vertex is not supported with vecS label storage: erasing from the underlying vector invalidates all label-to-vertex mappings after the erased position"
510+
);
504511
return graph_detail::remove_labeled_vertex(_map, _graph, l);
505512
}
506513

@@ -642,6 +649,13 @@ class labeled_graph< Graph*, Label, Selector >
642649
/** Remove the vertex with the given label. */
643650
void remove_vertex(Label const& l)
644651
{
652+
static_assert(
653+
!is_same<
654+
typename graph_detail::container_traits<map_type>::category,
655+
graph_detail::vector_tag
656+
>::value,
657+
"remove_vertex is not supported with vecS label storage: erasing from the underlying vector invalidates all label-to-vertex mappings after the erased position"
658+
);
645659
return boost::remove_vertex(vertex(l), *_graph);
646660
}
647661

test/Jamfile.v2

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ alias graph_test_regular :
3131
# and implementation of graph data structures and adaptors.
3232
[ run test_graphs.cpp ]
3333
[ run index_graph.cpp ] # TODO: Make this part of the test_graphs framework
34+
35+
[ compile-fail concept_tests/labeled_graph/compile_fail_remove_vertex_vecS.cpp ]
3436
[ run labeled_graph.cpp ]
37+
3538
[ run finish_edge_bug.cpp ]
3639

3740
[ run transitive_closure_test.cpp /boost/timer//boost_timer ]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//=======================================================================
2+
// Copyright 2026
3+
// Author: Becheler Arnaud
4+
//
5+
// Distributed under the Boost Software License, Version 1.0. (See
6+
// accompanying file LICENSE_1_0.txt or copy at
7+
// http://www.boost.org/LICENSE_1_0.txt)
8+
//=======================================================================
9+
10+
// This file must FAIL to compile.
11+
// remove_vertex is not supported when the label map uses vecS storage because
12+
// erasing from the underlying vector invalidates all label-to-vertex mappings
13+
// after the erased position.
14+
15+
#include <boost/graph/adjacency_list.hpp>
16+
#include <boost/graph/labeled_graph.hpp>
17+
18+
int main()
19+
{
20+
typedef boost::labeled_graph<
21+
boost::adjacency_list<boost::listS, boost::listS, boost::directedS>,
22+
unsigned,
23+
boost::vecS
24+
> Graph;
25+
26+
Graph g;
27+
g.add_vertex(0u);
28+
g.remove_vertex(0u); // should trigger static_assert
29+
}

test/labeled_graph.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ void test_remove_vertex_suite(Label l1, Label l2, Label l3)
234234
g.add_vertex(l3);
235235
BOOST_ASSERT(num_vertices(g) == 3);
236236

237+
// TODO: this is broken when backed by vecS + unsigned because
238+
// erasing middle element invalidates others.
237239
g.remove_vertex(l2);
238240
BOOST_ASSERT(num_vertices(g) == 2);
239241
BOOST_ASSERT(g.vertex(l2) == LabeledGraph::null_vertex());
@@ -384,7 +386,8 @@ void test_remove_vertex_all_types()
384386
>("a", "b", "c");
385387

386388
// adjacency_list + vecS not supported (unstable removal would require remapping the map)
387-
389+
// TODO: fix or not but document
390+
388391
// adjacency_list + listS (stable removal)
389392
test_remove_vertex_suite<
390393
labeled_graph<adjacency_list<listS, listS, directedS>, string, mapS>
@@ -394,10 +397,10 @@ void test_remove_vertex_all_types()
394397
labeled_graph<adjacency_list<listS, listS, undirectedS>, string, mapS>
395398
>("a", "b", "c");
396399

397-
// unsigned labels (vecS)
398-
test_remove_vertex_suite<
399-
labeled_graph<adjacency_list<listS, listS, directedS>, unsigned, vecS>
400-
>(0u, 1u, 2u);
400+
// unsigned labels (vecS) : should not compile because static assert prevents removing vertices now
401+
// test_remove_vertex_suite<
402+
// labeled_graph<adjacency_list<listS, listS, directedS>, unsigned, vecS>
403+
// >(0u, 1u, 2u);
401404

402405
// Pointer specialization:
403406
// temporarily attach labels to it without copying.
@@ -417,9 +420,9 @@ void test_remove_vertex_all_types()
417420
labeled_graph<directed_graph<>*, string, hash_mapS>
418421
>("a", "b", "c");
419422

420-
// unsigned labels
421-
test_remove_vertex_suite_ptr_variant<
422-
adjacency_list<listS, listS, directedS>,
423-
labeled_graph<adjacency_list<listS, listS, directedS>*, unsigned, vecS>
424-
>(0u, 1u, 2u);
423+
// unsigned labels (vecS) : should not compile because static assert prevents removing vertices now
424+
// test_remove_vertex_suite_ptr_variant<
425+
// adjacency_list<listS, listS, directedS>,
426+
// labeled_graph<adjacency_list<listS, listS, directedS>*, unsigned, vecS>
427+
// >(0u, 1u, 2u);
425428
}

0 commit comments

Comments
 (0)