简体   繁体   中英

performance of find in an unordered_map

I know this is probably a stupid question, but I wanted to make sure and I couldn't readily find this information.

What is the performance characteristic of find() in an unordered map? Is it as fast/nearly as fast as a normal lookup?

Ie

std::string defaultrow = sprite.attribute("defaultrow").value();
auto rclassIt = Rows::NameRowMap.find(defaultrow);
if (rclassIt != Rows::NameRowMap.end())
    defRow = rclassIt->second;

vs.

std::string defaultrow = sprite.attribute("defaultrow").value();
defRow = Rows::NameRowMap[defaultrow];

where Rows::NameRowMap is a unordered map mapping a string index to an int.

In my case, I don't know for certain if the key will exist before hand, so the first solution seemed safer to me, but if I can guarantee existence, is the second case faster (ignoring the extra checks I'm doing)? and if so, why? If it matters, I'm using the 1.46 boost implementation

It's pretty possible that operator[] uses find and insert internally. For example, IIRC that's the case with Miscrosoft's std::map implementation.

EDIT: What I was trying to say is that operator[] is not magical, it still has to do a lookup first. From what I see in Boost 1.46.0 both find and said operator use find_iterator internally.

Usually it's better to use find for lookups, because your code will be more reusable and robust (eg you will never insert something accidentally), especially in some kind of generic code.

find and operator[] on an unordered container are O(1) average, O(n) worst-case -- it depends on the quality of your hash function.

They have the same amortized complexity of O(1), but the operator also creates a new element when the value is not found. If the value is found, performance difference should be minor. My boost is a little old - version 1.41, but hopefully it does not matter. Here is the code:

// find
//
// strong exception safety, no side effects
template <class H, class P, class A, class G, class K>
BOOST_DEDUCED_TYPENAME hash_table<H, P, A, G, K>::iterator_base
hash_table<H, P, A, G, K>::find(key_type const& k) const
{
    if(!this->size_) return this->end();

    bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
    node_ptr it = find_iterator(bucket, k);

    if (BOOST_UNORDERED_BORLAND_BOOL(it))
        return iterator_base(bucket, it);
    else
        return this->end();
}

// if hash function throws, basic exception safety
// strong otherwise
template <class H, class P, class A, class K>
    BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::value_type&
hash_unique_table<H, P, A, K>::operator[](key_type const& k)
{
    typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type;

    std::size_t hash_value = this->hash_function()(k);
    bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);

    if(!this->buckets_) {
        node_constructor a(*this);
        a.construct_pair(k, (mapped_type*) 0);
        return *this->emplace_empty_impl_with_node(a, 1);
    }

    node_ptr pos = this->find_iterator(bucket, k);

    if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
        return node::get_value(pos);
    }
    else {
        // Side effects only in this block.

        // Create the node before rehashing in case it throws an
        // exception (need strong safety in such a case).
        node_constructor a(*this);
        a.construct_pair(k, (mapped_type*) 0);

        // reserve has basic exception safety if the hash function
        // throws, strong otherwise.
        if(this->reserve_for_insert(this->size_ + 1))
            bucket = this->bucket_ptr_from_hash(hash_value);

        // Nothing after this point can throw.

        return node::get_value(add_node(a, bucket));
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM