Basically I'm looking for the functionality akin to std::map::extract.
TL;DR
I currently have a multi-index container with two views: insert order and sorted by an "id" member function of the contained element. The multi-index container currently operates on elements of a pointer type. However, the container fully owns the objects it contains and I'd like to change the contained elements to be unique_ptr instead.
However, it looks non-trivial to do "remove a given element preserving its value" step with unique_ptr.
Since the pointer is to an abstract base class, I can't use swap() because this would require me to construct an "empty" object of an abstract type.
Edit: Thanks to the fact that compiler explorer supports linking to 3rd party libraries, I was able to create what I think is the minimal reproducible example
#include <memory>
#include <vector>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/tag.hpp>
#include <boost/multi_index_container.hpp>
class Base {
public:
virtual size_t GetId() const = 0;
virtual ~Base() = default;
};
class Derived : public Base {
public:
size_t GetId() const { return 42; }
};
int main(int, char**) {
// A tag to view elements in the order of insertion.
struct Sequenced{};
// A tag to view elements in the order sorted by type id.
struct Ordered{};
using ContainerType = boost::multi_index_container<
// Elements are pointers to Base.
std::unique_ptr<Base>,
boost::multi_index::indexed_by<
boost::multi_index::sequenced<boost::multi_index::tag<Sequenced>>,
boost::multi_index::hashed_unique<
boost::multi_index::tag<Ordered>,
boost::multi_index::const_mem_fun<Base, size_t,
&Base::GetId>>>>;
ContainerType container;
// Insert an element.
auto& ordered_view = container.get<Ordered>();
auto new_element = std::make_unique<Derived>();
auto insert_result = ordered_view.insert(std::move(new_element));
if (!insert_result.second) return -1;
// Now I just need to extract the element with GetId == 42
// This works only starting with boost v1.74
std::unique_ptr<Base> extracted = std::move(ordered_view.extract(42).value());
}
Starting with boost v1.74, hashed views support "extract" member function. I don't think it's possible to do what I want to do prior to that version. The swap trick mentioned in the comments won't work as it does not exist for hashed views. And furthermore, for the views it does exist (sequenced) it actually swaps the whole container, not individual elements.
I'd suggest upgrading. If that's not an option, I can only see a helper implementation that works if
unique_ptrto be non-nullI'll demonstrate the first option using a chosen INVKEY of
-1(0xFFFFFFFF) to act as the temporary "deletion" key:Demo Program
Live On Coliru
Prints
Comfirm Compiler Explorer Boost 1.73.0