0
votes

I'm looking to remove one key - value element from an std::map and keep the value which was stored in this map. Just removing it is not enough, I need the key and value which was stored for other things.

My example is something like this:

std::map<const Class1 *, std::unique_ptr<Class 2>> myMap;

I would like to extract the key and value from the std::map. Simply moving it away is not an option, since this will put the std::map in an incorrect state.

I found the std::extract function, which I can use for an std::set, but not for an std::map. I cannot find any example online showing how I can extract the key and value from this map.

I would like to do something like this:

auto keyAndValue = myMap.extract(myMap.find(instanceOfClass1));

auto key = keyAndValue.someMethod();

auto value = std::move(keyAndValue.someOtherMethod());

I thought I could use key() and value(), as described in some examples. But this does not work, I get an error.

error C2039: 'value': is not a member of
'std::_Node_handle<std::_Tree_node<std::pair<const
_Kty,_Ty>,std::_Default_allocator_traits<_Alloc>::void_pointer>,_Alloc,std::_Node_handle_map_base,_Kty,_Ty>'
2
Did you try mapped() instead of value()? - Mark
If you're using the pointer to an instance as the key, why not just make it a member of that instance, and skip the map? As it is now, I'd think you could find, then move the unique ptr off iterator.second, then erase(iterator) -- so nothing fundamentally different from the duplicate link JeJo posted. Care to set up a mcve with some dummy classes? - Kenny Ostrom
Maybe I do not understand your question correctly. But there is a std::map extract function in C++17. Or are you using older C++ version? - Armin Montigny
@ArminMontigny I don't know how to use the result I get from this extract method and I cannot find any documentation on it - Houbie
@KennyOstrom I'll add a small executable code example - Houbie

2 Answers

1
votes

You answered the question by yourself.

I just want to add a complete example. Please see:

#include <iostream>
#include <map>
#include <functional>
#include <memory>

struct Class1
{
    void someMethod() const  { std::cout << "Some Method from class 1\n";}
};
struct Class2
{
    Class2(const int i) : test(i) {}
    void someOtherMethod() const  { std::cout << "Some other Method from class 2.  Index: " << test << '\n';}
    int test{0};
};

int main()
{
    Class1 cl1_1{}, cl1_2{}, cl1_3{};

    std::map<const Class1 *, std::unique_ptr<Class2>> myMap;
    // Populate map
    myMap[&cl1_1] = std::make_unique<Class2>(1);
    myMap[&cl1_2] = std::make_unique<Class2>(2);
    myMap[&cl1_3] = std::make_unique<Class2>(3);

    // Extract data    
    auto keyAndValue = myMap.extract(myMap.find(&cl1_1));

    // Get key and value
    auto key = keyAndValue.key();
    auto value = std::move(keyAndValue.mapped());

    // Call methods
    key->someMethod();
    value->someOtherMethod();

    return 0;
}
0
votes

The answer was suggested by Mark. For an std::map, I need to use mapped() on the node I get, not value. Thanks a lot!

So, like this

auto keyAndValue = myMap.extract(myMap.find(instanceOfClass1));

auto key = keyAndValue.key();

auto value = std::move(keyAndValue.mapped());