6

I know that std::set does not allow non-const access to it's items. I know that it's impossible to move items out of a the set – because any sort of non-const access might break the ordering of the set.

However, we CAN erase an item from the set. This doesn't break it, because it just forces the set to restructure. How come then, we can't 'pop' an item? Why can't I get out the item and erase it at the same time?

The reason I'm asking is - I need an ordered container of unique_ptrs. Occasionally I need to 'pop' unique_ptrs from one container and transfer it them to another. They must be ordered be a custom functor that I've made.

I don't see why a pop functionality shouldn't be allowed?

Thor Correia
  • 1,159
  • 1
  • 12
  • 20
  • 7
    https://en.cppreference.com/w/cpp/container/set/extract ? – Evg Aug 18 '18 at 20:16
  • `pop` needs the notion of a linear order. You pop from one of the ends of that order. A set does not have such an order. – Adrian W Aug 18 '18 at 20:18
  • 2
    @AdrianW Correct for a mathematical set, but `std::set` is ordered though. – juanchopanza Aug 18 '18 at 20:19
  • That would have quite different semantics as compared to a list: if you were able to pop from a set, you would pop the smallest or the biggest member. However if you pop from a list, you remove the first or the last member in terms of the linear order of the list, not of the order of the _values_ of the list. – Adrian W Aug 18 '18 at 20:22
  • @AdrianW What I'm saying is -- If you can erase a member from std::set without breaking the ordering, how come you can't 'pop' that same item? i.e. why is there not a function similar to erase, but which returns the item as well? – Thor Correia Aug 18 '18 at 20:24
  • @Ron Not really -- you can erase an item without messing up the order of the set. This theoretical function would do the same but also return the item that was removed. – Thor Correia Aug 18 '18 at 20:25
  • @Evgeny That's beautiful except I don't think it's fully supported yet. Reason being, with g++ --std=c++17, I still get "no member named 'extract' in (theSet)" – Thor Correia Aug 18 '18 at 20:30
  • Update your gcc. I checked gcc 7.1.0, and it works. – Evg Aug 18 '18 at 20:34

2 Answers2

7

To extract a node from std::set you can use extract(...) member function, that was introduced in C++17:

#include <set>
#include <iostream>

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

    std::cout << "Original set: ";
    for (auto e : set)
        std::cout << e << ' ';
    std::cout << '\n';

    auto first = set.extract(set.begin());
    std::cout << "Extracted value: " << first.value() << '\n';

    std::cout << "New set: ";
    for (auto e : set)
        std::cout << e << ' ';
    std::cout << '\n';
}

Output:

Original set: 1 2 3 5 7
Extracted value: 1
New set: 2 3 5 7
Evg
  • 25,259
  • 5
  • 41
  • 83
2

This is a misunderstanding of what pop() does in C++. For example, stack::pop() removes the top element of the stack, but it does not return a copy of it. That's because the copy constructor of the type being returned might throw an exception, and if that happened, the object would have already been removed from the stack, so there would be no way to recover it. So the idiom is to get a reference to the top element with stack::top() and copy it, then use stack::pop() to remove it.

Same thing for a set: if you combined erasing an element with returning a copy of it you'd run the risk of losing it.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • I agree that the OP may not understand what pop() does, but I don't see why that stops it being implemented for a set. –  Aug 18 '18 at 20:53
  • 2
    @NeilButterworth — I don’t understand your comment. Erase-and-copy is not exception-safe. It risks losing the object. Doesn’t matter whether it’s set, a vector, or any other kind of container. – Pete Becker Aug 18 '18 at 21:29
  • I meant I don't see why technically pop() (i.e. discard first entry, without copying, as for stack) could not be implemented for a set. –  Aug 18 '18 at 21:31
  • Of course it could. But that’s not what the question is asking for. – Pete Becker Aug 19 '18 at 00:45