std::set::extract(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

✨ std::set::extract(3) ✨

okay bestie, gather round, because we're about to talk about the C++ Standard Library function std::set::extract, and honestly? it's kinda iconic. this is a std::set member function, and the way it lets you yoink nodes right out of a container is giving main character energy fr fr. no cap, this one's a banger. πŸ’…


πŸŽ€ SYNOPSIS πŸŽ€

okay so here's the vibe, look at these overloads:

node_type extract( const_iterator position ); (1) (since C++17)
node_type extract( const Key& k );            (2) (since C++17)
template< class K >                           (3) (since C++23)
node_type extract( K&& x );
  1. this one unlinks the node that holds the element that position is pointing at, and hands you back a node handle that owns it. slay.
  2. if the container has an element with a key equivalent to k, it unlinks that node from the container and returns a node handle that owns it. otherwise? you get an empty node handle. no drama, just emptiness. 😭
  3. same as (2), literally the same. but this overload only participates in overload resolution if the qualified-id Compare::is_transparent is valid and denotes a type, AND neither iterator nor const_iterator is implicitly convertible from K. why? because it lets you call this function without ever constructing an instance of Key. efficiency queen. πŸ‘‘

in either case (and this is important bestie), no elements are copied or moved β€” only the internal pointers of the container nodes are repointed (rebalancing may occur, as with erase()). it's giving minimal effort, maximum impact. πŸ¦‹

extracting a node invalidates only the iterators to the extracted element. pointers and references to the extracted element remain valid, but they cannot be used while the element is owned by a node handle β€” they become usable again if the element is inserted into a container. so like, hold onto that reference, but don't @ it while it's in node-handle jail. πŸ™ˆ


🌸 PARAMETERS 🌸

  • position β€” a valid iterator into this container. gotta be valid, bestie, don't come at it with a broken iterator.
  • k β€” a key to identify the node to be extracted. it's giving "which one of y'all is this."
  • x β€” a value of any type that can be transparently compared with a key identifying the node to be extracted. transparent comparison? we love to see it. ✨

πŸ’– RETURN VALUE πŸ’–

a node handle that owns the extracted element. or, in the case of overloads (2,3) where the element isn't found? an empty node handle. it's giving "sorry babe, not here." πŸ’€


🧚 EXCEPTIONS 🧚

  1. throws nothing. literally nothing. icon behavior.

2, 3. any exceptions thrown by the Compare object. so if your comparator is messy, that's on you, not on extract. πŸ™ˆ


πŸ“ COMPLEXITY πŸ“

  1. amortized constant. fast. effortless. the way it should be. πŸ”₯

2, 3. log(size()). logarithmic, which is still cute, just doing a little more work. ngl, still slaps.


🌈 NOTES 🌈

okay so this is the tea: extract is the only way to take a move-only object out of a set. the only way. periodt. πŸ’…

std::set<move_only_type> s;
s.emplace(...);
move_only_type mot = std::move(s.extract(s.begin()).value());

see how that works? you extract the node handle, then .value() gives you the move-only object, and you std::move it out. chef's kiss. πŸ‘‘


⭐ FEATURE-TEST MACRO ⭐

here's the feature-test macro table, and yes, I'm including every single detail because bestie, we don't skip:

Feature-test macroValueStdFeature
__cpp_lib_associative_heterogeneous_erasure202110L(C++23)Heterogeneous erasure in associative containers and unordered associative containers, (3)

that macro is long, but it's valid and it's doing its job. 🫢


πŸ¦‹ EXAMPLE πŸ¦‹

okay so here's the full example, run it and watch the magic:

// Run this code

#include <algorithm>
#include <iostream>
#include <string_view>
#include <set>

void print(std::string_view comment, const auto& data)
{
    std::cout << comment;
    for (auto datum : data)
        std::cout << ' ' << datum;

    std::cout << '\n';
}

int main()
{
    std::set<int> cont{1, 2, 3};

    print("Start:", cont);

    // Extract node handle and change key
    auto nh = cont.extract(1);
    nh.value() = 4;

    print("After extract and before insert:", cont);

    // Insert node handle back
    cont.insert(std::move(nh));

    print("End:", cont);
}

and the output is literally right here:

Start: 1 2 3
After extract and before insert: 2 3
End: 2 3 4

see how we yoinked 1, changed it to 4, and then slid it back in? that's the whole vibe. no elements were harmed (or copied, or moved) in the making of this example. iconic. 🌟


🌸 SEE ALSO 🌸

  • merge β€” splices nodes from another container (C++17) (public member function). the social butterfly of node operations. πŸ¦‹
  • insert β€” inserts elements or nodes (since C++17) (public member function). the classic. the reliable one. the one you already know and love. πŸ’–
  • erase β€” erases elements (public member function). not extract, just erase. know the difference bestie. πŸ’…

and that's the whole page, bestie! no cap, you're now a std::set::extract expert. this manual page came from http://cppreference.com, version 2024.06.10, dated 2024.06.10, and honestly? it ate. πŸ’…βœ¨πŸŽ€πŸ¦‹πŸŒΈπŸ’–πŸ«Ά

periodt. πŸ’œ

πŸ“¦ where this page comes from