Moving an object out of a set
You can use extract
to remove the corresponding node from the set. This gives you a handle to the node. Once you have the handle, you can move the item out of the handle.
template<class T>
T find_and_remove(std::set<T>& s, T const& elem) {
auto iterator = s.find(elem);
if(iterator == s.end() {
throw std::invalid_argument("elem not in set");
}
// Remove element, return node handle
auto node_handle = s.extract(iterator);
return std::move(node_handle.value());
}
Alternatively, if you already have the iterator to the node, you can write it like this:
template<class T>
T remove_from_set(std::set<T>& s, std::set<T>::iterator it) {
return std::move(s.extract(it).value());
}
Moving the value transfers ownership of any resources owned by the value. For example, if the set contains a string, the contents of the string won't be deleted, and any iterators to the string won't be invalidated.
The caveat of this is that if you had pointers or references to the object from when it was still in the set, these will be invalidated.
Extracting the object itself without a move and without invalidating any pointers or references to the object
This is the less common case, but if you had a reference or pointer to the object in the set, you may want to do this.
Again, we can use the extract
function:
auto node_handle = s.extract(my_object);
Or:
auto node_handle = s.extract(my_iterator);
You can access the stored object with node_handle.value()
, which returns a reference to the object. The object won't be deleted until the node_handle
is deleted, and if you need to extend it's lifetime further, you can return the node_handle
from a function without the object being deleted.