# Node Handles¶

## Summary¶

Concurrent associative containers in TBB (concurrent_unordered_{map, multimap, set, multiset}, concurrent_{map, multimap, set, multiset}) store data in individually allocated, connected nodes. It makes possible to transfer data between containers with compatible node types by changing the connections, without copying or moving the actual data.

A node handle (supported since C++11) is a container-specific move-only nested type (exposed as container::node_type) that represents a node outside of any container instance. It allows reading and modifying the data stored in the node, and inserting the node into a compatible container instance. The following containers have compatible node types and may exchange nodes:

• concurrent_unordered_{map,multimap} classes with the same key_type, mapped_type and allocator_type

• concurrent_unordered_{set,multiset} classes with the same value_type and allocator_type

• Preview concurrent_{map,multimap} classes with the same key_type, mapped_type and allocator_type

• Preview concurrent_{set,multiset} classes with the same value_type and allocator_type

Default-constructed node handles are empty, i.e. do not represent a valid node. A non-empty node handle is typically created when a node is extracted out of a container, e.g. with the unsafe_extract method. It stores the node along with a copy of the container’s allocator. If the node is then moved into another handle or inserted into a container, the moved-from handle becomes empty. Upon assignment or destruction, a non-empty node handle destroys the stored data and deallocates the node.

## Members¶

class node-handle { // Exposition-only name; use container::node_type instead
public:
typedef container-specific key_type;    // Only for maps
typedef container-specific mapped_type; // Only for maps
typedef container-specific value_type;  // Only for sets
typedef container-specific allocator_type;

node-handle();
node-handle(node-handle&& nh);
~node-handle();

node-handle& operator=(node-handle&& nh);

void swap(node-handle& nh);

bool empty() const;
explicit operator bool() const;

key_type& key() const;       // Only for maps
mapped_type& mapped() const; // Only for maps
value_type& value() const;   // Only for sets
allocator_type get_allocator() const;
};


The following table provides additional information on the members of a node handle class:

Member, Description

node-handle()

Constructs an empty node handle.

node-handle(node-handle&& nh)

Constructs a node handle that takes ownership of the node from nh, leaving it in the empty state.

~node-handle()

If *this is not empty, destroys and deallocates the owned node.

node-handle& operator=(node-handle&& nh)

If *this is not empty, destroys and deallocates the owned node. In either case, takes ownership of the node from nh, leaving it in the empty state.

Returns: A reference to *this.

void swap(node-handle& nh)

Exchanges the nodes owned by *this and nh.

bool empty()

Returns: true if the node handle is empty, false otherwise.

explicit operator bool() const

Equivalent to !nh.empty().

key_type& key() const

Available only for map node handles.

Returns: Reference to the key of the element stored in the owned node. The behavior is undefined if the node handle is empty.

mapped_type& mapped() const

Available only for map node handles.

Returns: Reference to the value of the element stored in the owned node. The behavior is undefined if the node handle is empty.

value_type& value() const

Available only for set node handles.

Returns: Reference to the element stored in the owned node. The behavior is undefined if the node handle is empty.

allocator_type get_allocator() const;

Returns: Copy of the stored allocator instance. The behavior is undefined if the node handle is empty.

## Example¶

The following simplified example shows how to transfer data between containers with the help of a node handle:

#include "tbb/concurrent_unordered_map.h"

int main() {
using Map = tbb::concurrent_unordered_map<int, int>;
Map map = {{1, 1}, {2, 2}, {3, 3}};

// Extract an element from the container
Map::node_type nh = map.unsafe_extract(2);

// Change key/value of handled element
nh.key() = 7;
nh.mapped() = 9;

// Insert an element to the new container
Map map2;
map2.insert(std::move(nh));
}