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.
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; };
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. |
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)); }