'Erasing element from std::unordered_map by reference to element from std::list

I'm implementing my LRUCache and I have an issue with understanding the removal from std::unordered_map. All the examples in The Internet show that it's possible to remove an element from std::unordered_map using reference to element from std::list (by using std::list::back()). Why is that so? I checked out the documentation for std::unordered_map::erase() and it accepts map iterator or key as an argument, but defenitely not a reference to an element in another data structure? Is there some specific converstion or somethign about iterators I don't understand? Thank you in advance!

P.S. I would appriciate any comments on my code structure and implementation.

Here's my code for cache:

#ifndef LRUCACHE_H
#define LURCACHE_H

#include <list>
#include <unordered_map>
#include <assert.h>
#include <iostream>

template<typename T, typename KeyT = T>
class LRUCache
{

using ListItr = typename std::list<T>::iterator;

public:
    LRUCache(int size) : m_size(size)
    {

    }

    int size() const
    {
        return m_size;
    }

    bool isFull() const
    {
        return m_size == m_cache.size();
    }

    bool contains(const KeyT& key)
    {
        m_lookup_table.find(key) != m_lookup_table.end();
    }

    T get(const KeyT& key)
    {
        auto hit = m_lookup_table.find(key);
        assert("No such element present" && hit != m_lookup_table.end());
        if (hit != m_lookup_table.begin()) {
            m_cache.splice(m_cache.begin(), m_cache, hit->second);
        }
        return *(hit->second);
    }

    void set(const KeyT& key, const T& value)
    {
        auto hit = m_lookup_table.find(key);
        if (hit == m_lookup_table.end()) {
            if (isFull()) {
                m_lookup_table.erase(m_cache.back()); // <-- I don't understand this
                m_cache.pop_back();
            }
            m_cache.push_front(value);
            m_lookup_table[key] = m_cache.begin();
            return;
        }

        if (hit->second != m_cache.begin()) {
            m_cache.splice(m_cache.begin(), m_cache, hit->second);
        }
    }

    void display() const
    {
        for (const auto& e : m_cache) {
            std::cout << e << " ";
        }
        std::cout << std::endl;
    }

private:
    int m_size;
    std::list<T> m_cache;
    std::unordered_map<KeyT, ListItr> m_lookup_table;
};

#endif


Solution 1:[1]

There is an overload of erase that accepts Key (which in your case equals KeyT), not the iterator: https://en.cppreference.com/w/cpp/container/unordered_map/erase.

Note that back from std::list doesn't return an iterator, but the element (in your case T): https://en.cppreference.com/w/cpp/container/list/back

So my guess is that the code only compiles for your default case when KeyT = T.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1