Using an object reference as a key in std::unordered_map
Asked Answered
D

2

12

I'd like to know if it is possible to use an object reference as a key in an unordered_map container in C++.

#include <unordered_map>

class Object {
    int value;
};

struct object_hash {
  inline size_t operator()(const Object& o) const { return 0; }
};

std::unordered_map<Object&, int, object_hash> map;

When trying to compile this simple snippet, I got some errors about methods redefinition:

Using clang with libc++

/usr/include/c++/v1/unordered_map:352:12: error: class member cannot be redeclared

size_t operator()(const _Cp& __x) const

Using gcc 4.6 with libstdc++

/usr/include/c++/4.6/bits/hashtable_policy.h:556:5: error: ‘std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type& std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::operator [with _Key = Object&, _Pair = std::pair, _Hashtable = std::_Hashtable, std::allocator >, std::_Select1st >, std::equal_to, object_hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, false, false, true>, std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type = int]’ cannot be overloaded

/usr/include/c++/4.6/bits/hashtable_policy.h:537:5: error: with ‘std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type& std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::operator[](const _Key&) [with _Key = Object&, _Pair = std::pair, _Hashtable = std::_Hashtable, std::allocator >, std::_Select1st >, std::equal_to, object_hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, false, false, true>, std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type = int]’

If I use an old gnu hash_map instead (__gnu_cxx::hash_map), I don't have this problem.

Is this some limitation imposed by the new standard, and if so, why?

Is there a way to workaround this limitation?

Disrupt answered 22/5, 2012 at 14:13 Comment(0)
F
16

The new standard defines std:reference_wrapper<T> to work around this limitation.

It is implicitly convertible to a T& so that it is transparent, and like references guarantee there is no null state, however unlike references it can be re-seated.

More information in Using std::reference_wrapper as key in std::map.

Fiddlewood answered 22/5, 2012 at 15:26 Comment(0)
T
0

I ran into this and my colleagues helped me discover a solution that I thought was worth sharing:

struct RefWapperAddressHash
{
    std::size_t operator()( Object const& obj ) const
    {
        std::hash< Object const* > theHash{};
        return theHash( &obj );
    }
};

std::unordered_map< std::reference_wrapper< Object >, int, RefWrapperAddressHash > m_map;

This uses std::hash's ctor : template< class T > struct hash<T*>;

Tanjatanjore answered 17/9, 2021 at 18:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.