I still think you are better off using a std::list
. Consider:
#include <iostream>
#include <list>
class A
{
public:
int i_;
A(int i) : i_(i) {}
A(const A&) = delete;
A(A&&) = delete;
void operator=(const A&) = delete;
void operator=(A&&) = delete;
};
int main()
{
std::list< A > l;
// inserting elements
auto it1 = l.emplace( l.end(), 1 ); // note: complexity is O(1)
auto it2 = l.emplace( l.end(), 2 );
auto it3 = l.emplace( l.end(), 3 );
auto it4 = l.emplace( l.end(), 4 );
// deleting an element by iterator
l.erase( it2 ); // note: complexity is O(1)
// note: it2 is now invalid
// accessing element by iterator
it3->i_ = 42;
for( const auto& e : l ) {
std::cout << e.i_ << std::endl;
}
// silence compiler warnings
(void)it1;
(void)it4;
}
In the above, all your use-cases should have an efficient implementation. You can avoid the overhead of calculating the hash and having the hash-map. It's even more efficient as your hash-based approach, for the list both operations are O(1) and much more light-weigth wrt the implementation. And storing the iterator is not much different from storing a pointer to the element directly.
Also, it is guaranteed that this works for non-copyable and non-movable types. See the documentation for std::list::emplace
.