This documentation is being rewritten. If something looks off, please cross-check with the Boost 1.91.0 Boost.Graph docs and open an issue.

Property Maps

Algorithms need data on vertices and edges: weights, distances, colors, predecessors, communities. A property map is a lightweight accessor that reads and writes this data. You own the storage; the property map just knows how to index into it.

This separation lets you choose the allocation strategy (stack array, heap vector, std::map, even a lambda) while algorithms access the data through a uniform get(map, key) / put(map, key, value) interface.

The trade-off is that the complexity shifts to the point where you wrap your storage into this uniform interface: creating the property map.

How to attach data to a graph

There are three approaches. Start with bundled properties unless you have a specific reason not to.

Define a struct for your vertex/edge data. Access members with get(&Struct::member, g).

struct City { std::string name; int population; };
struct Road { double distance; int lanes; };

using Graph = adjacency_list<vecS, vecS, directedS, City, Road>;

Graph g(3);
g[0].name = "Paris";
auto dist_map = get(&Road::distance, g);  // property map for all edge distances
Use when: you own the graph type and know the properties at compile time. This is the simplest and most readable approach.

2. External properties

Store data in your own container, then wrap it as a property map. The graph object knows nothing about this data.

std::vector<int> dist(num_vertices(g));
auto dist_map = make_iterator_property_map(dist.begin(), get(vertex_index, g));
Use when: the data is temporary (algorithm output), you cannot modify the graph type, or you need to control allocation (custom allocator, memory-mapped storage, reuse across calls).

3. Internal property tags (legacy)

Attach properties via property<> tags at graph definition time. Access with get(tag, g).

using Graph = adjacency_list<vecS, vecS, directedS,
    no_property,
    property<edge_weight_t, int>>;

auto weight = get(edge_weight, g);
Use only with existing code that already uses this style. Prefer bundled properties for new code. Tags are harder to read and do not compose well when you need multiple properties.
Most algorithms accept all three approaches interchangeably. The algorithm does not know or care where the data lives.
When an algorithm parameter like color_map is not explicitly provided, most algorithms allocate a temporary std::vector internally and wrap it with the graph’s vertex_index map. This is why many algorithms work out of the box with no property map arguments — but it requires VertexList=vecS (which provides the built-in vertex index).
Property maps are not iterable. There is no begin()/end(). To read all values, iterate over the graph’s vertices or edges and look up each one: for (auto v : make_iterator_range(vertices(g))) std::cout << get(pm, v);

Creation reference

Storage Create with Example

Bundled struct member

get(&Struct::member, g)

auto w = get(&Road::cost, g);

Internal property tag

get(tag, g)

auto idx = get(vertex_index, g);

std::vector + index map

make_iterator_property_map(iter, index)

auto pm = make_iterator_property_map(vec.begin(), get(vertex_index, g));

Raw C array

Use directly

int dist[N]; /* pass as property map argument */

std::map (non-integer keys)

make_assoc_property_map(map)

std::map<Vertex,int> m; auto pm = make_assoc_property_map(m);

Auto-growing vector

vector_property_map<T>(n, index)

vector_property_map<double> pm(num_vertices(g), get(vertex_index, g));

Computed from a callable

make_function_property_map<Key>(f)

auto pm = make_function_property_map<Vertex>([&](Vertex v){ return degree(v,g); });

Transformed view of another map

make_transform_value_property_map(f, pm)

auto pm2 = make_transform_value_property_map([](double d){ return d*2; }, pm);

Vertex degree (read-only)

make_degree_map(g)

auto deg = make_degree_map(g);

Constant value for all keys

static_property_map<T>(value)

static_property_map<double> pm(1.0);

Discard output (placeholder)

dummy_property_map()

dummy_property_map pm;

Memory-efficient 2-color map

make_one_bit_color_map(n, index)

auto cm = make_one_bit_color_map(num_vertices(g), get(vertex_index, g));

Memory-efficient 4-color map

make_two_bit_color_map(n, index)

auto cm = make_two_bit_color_map(num_vertices(g), get(vertex_index, g));

The interface

Every property map supports at most three operations:

value = get(pm, key);          // read (Readable)
put(pm, key, value);           // write (Writable)
reference = pm[key];           // reference access (Lvalue only)

get() returns a copy of the value. For Lvalue property maps, pm[key] returns a reference (const or mutable depending on the map).

To deduce types from a property map at compile time, use property_traits:

using Value = typename property_traits<Map>::value_type;
using Key   = typename property_traits<Map>::key_type;
using Cat   = typename property_traits<Map>::category;

This is the property map equivalent of std::iterator_traits.

Property map categories

When reading algorithm documentation, each parameter is tagged with a direction: IN, OUT, or UTIL/OUT. These correspond to property map categories that determine what operations the algorithm will perform on the map.

Category Algorithm tag What it means

Readable

IN

The algorithm only reads: value = get(pm, key)

Writable

OUT

The algorithm only writes: put(pm, key, value)

ReadWrite

UTIL/OUT

The algorithm reads and writes: both get and put

Lvalue

(rare)

pm[key] returns a reference to the stored value

For example, in dijkstra_shortest_paths, the weight_map parameter is tagged IN (the algorithm reads edge weights but never modifies them), while distance_map is tagged UTIL/OUT (the algorithm both reads and writes distances during relaxation).

Passing a read-only map (like make_function_property_map) where the algorithm expects ReadWrite will fail to compile. The error message will mention put() not being found, which can be confusing if you do not know about these categories.

Headers

Header Contents

<boost/graph/properties.hpp>

Internal property tags (vertex_index, edge_weight, …​), get(tag, g)

<boost/property_map/property_map.hpp>

iterator_property_map, static_property_map, associative_property_map, dummy_property_map

<boost/property_map/vector_property_map.hpp>

vector_property_map

<boost/property_map/function_property_map.hpp>

make_function_property_map

<boost/property_map/transform_value_property_map.hpp>

make_transform_value_property_map

<boost/graph/property_maps/constant_property_map.hpp>

constant_property_map, make_constant_property

<boost/graph/property_maps/null_property_map.hpp>

null_property_map, make_null_property

<boost/graph/one_bit_color_map.hpp>

one_bit_color_map, make_one_bit_color_map

<boost/graph/two_bit_color_map.hpp>

two_bit_color_map, make_two_bit_color_map

Most algorithm headers pull in <boost/graph/properties.hpp> automatically, but external property map adaptors (iterator_property_map, vector_property_map, etc.) require explicit includes from <boost/property_map/>. Forgetting this is a common source of confusing template errors.

Complete example

All property map types in one file:

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/properties.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/property_map/vector_property_map.hpp>
#include <boost/property_map/function_property_map.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <iostream>
#include <map>
#include <string>
#include <vector>

struct City { std::string name; };
struct Road { double km; };

using namespace boost;
using Graph  = adjacency_list<vecS, vecS, directedS, City, Road>;
using Vertex = graph_traits<Graph>::vertex_descriptor;

int main() {
    Graph g(3);
    g[0].name = "Paris";
    g[1].name = "Lyon";
    g[2].name = "Marseille";
    add_edge(0, 1, Road{460}, g);
    add_edge(1, 2, Road{310}, g);
    add_edge(0, 2, Road{775}, g);

    auto index_map = get(vertex_index, g);

    // Bundled property map
    auto km_map = get(&Road::km, g);

    // std::vector + make_iterator_property_map
    std::vector<int> vec(num_vertices(g), -1);
    auto vec_map = make_iterator_property_map(vec.begin(), index_map);
    put(vec_map, vertex(0, g), 42);

    // Raw C array (usable directly as a property map)
    int arr[3] = {100, 200, 300};

    // std::map + make_assoc_property_map
    std::map<Vertex, std::string> labels;
    auto label_map = make_assoc_property_map(labels);
    put(label_map, vertex(0, g), "capital");

    // vector_property_map (auto-growing, heap-allocated)
    vector_property_map<double, decltype(index_map)> vpm(num_vertices(g), index_map);
    put(vpm, vertex(2, g), 3.14);

    // Computed from a lambda (read-only)
    auto degree_map = make_function_property_map<Vertex>([&](Vertex v) { return out_degree(v, g); });

    // Transformed view of another map
    auto miles_map = make_transform_value_property_map([](double d) { return d * 0.621371; }, km_map);

    // Constant for all keys
    static_property_map<double> unit(1.0);

    // Discard writes (placeholder)
    dummy_property_map sink;
    put(sink, vertex(0, g), 999); // silently ignored

    // All accessed the same way: get(map, key)
    std::cout << get(km_map, edge(0, 1, g).first) << " km\n";
    std::cout << get(vec_map, vertex(0, g)) << "\n";
    std::cout << get(arr, 1) << "\n";
    std::cout << get(label_map, vertex(0, g)) << "\n";
    std::cout << get(vpm, vertex(2, g)) << "\n";
    std::cout << get(degree_map, vertex(0, g)) << "\n";
    std::cout << get(miles_map, edge(0, 1, g).first) << " miles\n";
    std::cout << get(unit, vertex(0, g)) << "\n";
}
460 km
42
200
capital
3.14
2
285.831 miles
1