Reputation: 3450
I'm looking for an alternative to std::set
. I need it to support more operations then std::set
:
Move elements from one set to another without 'create new->copy->remove old'.
Split set at some position to get two sets (similar behaviour can be obtained using std::list splice
)
Set operations (like union) without unnecessary copying. std::set_union
will copy elements from sets A and B to set C which is inefficient if I only need set C and don't need A and B anymore.
Are there any implementations which support these operations or I need to write one myself?
Upvotes: 3
Views: 3967
Reputation: 620
I have the same problem as you with std::set
and there doesn't seem to be any sane way around with C++11, C++14. However in C++17 there are two new members added to std::set
which look very promising.
std::set::extract
allows extracting an entire node from the set. The removed node allows for obtaining a non-const reference to the underlying value effectively allowing for moving elements out of the set. It can be also inserted into another set without copying or moving the underlying value. std::set::merge
allows for merging two sets without copying or moving any elements, only updating internal pointers.
Upvotes: 6
Reputation: 1343
For point 1 & 3, you can use set<shared_ptr>
or some other smart pointer instead of store object directly in the set
. In this case, you should implement
bool operator<(shared_ptr<T> const & a, shared_ptr<T> const & b)
For point 2, there won't be such a method determined just by index because there's no index in set
. However, you can use something like filter
in ruby. Here predicator can be function, function object or closure.
remove_copy_if(foo.begin(), foo.end(), back_inserter(bar), some_predicator);
Upvotes: 2
Reputation: 720
The problem with trying to do what you suggest with a std::set
is that I do not believe you can move a value out of one. This is due to set iterators only returning const references to stop you changing the value and breaking the internal structure. You could probably const_cast
your way around this but I wouldn't recommend it. Even if you adopt this approach then you still have nodes in the tree being allocated and there is nothing you can do to avoid this overhead.
If you decide to implement your own set which supports moving values around, you should be able to get the Boost::Intrusive library (http://www.boost.org/doc/libs/1_52_0/doc/html/intrusive.html) to do the heavy lifting of keeping a set of sorted values. You would need to implement the code for managing the object lifetimes but that is easier than building a RB-tree implementation.
I implemented something similar for maps which stored the nodes in a std::list
. This allowed for moving elements between maps without copying either the node structure or the values being stored. If I get time I will try and tidy it up and post it here.
Upvotes: 2