Dmitri Nesteruk
Dmitri Nesteruk

Reputation: 23789

Correct way of 'upserting' items into map<key, shared_ptr<foo>>

I want to upsert (update or insert) items into a map<int,shared_ptr<PortfolioEntry>> structure. My current code is something like the following:

auto existing = positions.find(id);
if (existing == positions.end())
{
  positions[id] = make_shared<PortfolioEntry>(id, amount, price);
}
else
{
  // update positions[id]
}

So I'm wondering if it's the right way of doing things. Is find() efficient? Is assigning to positions[id] the right way to do this, or should I use some std::move construct?

Upvotes: 2

Views: 1375

Answers (3)

0x26res
0x26res

Reputation: 13902

The fastest way is to try to insert first and change the iterator value if nothing was inserted:

  template < class KeyType, class ElementType >
  bool SetAndCheckChanged(
    std::map< KeyType, ElementType >& the_map,
    KeyType const& key,
    ElementType const& new_value)
  {
    typedef typename std::map< KeyType, ElementType >::iterator Iterator;
    typedef typename std::pair< Iterator, bool > Result;
    Result result = the_map.insert(typename std::map< KeyType, ElementType >::value_type(key, new_value));
    if (!result.second)
    {
      if ( !(result.first->second == new_value ))
      {
        result.first->second = new_value;
        return true;
      }
      else
        return false; // it was the same
    }
    else
      return true;  // changed cause not existing
  }

Upvotes: 5

vmax33
vmax33

Reputation: 683

For upsert you can just use next line:

positions[id] = make_shared<PortfolioEntry>(id, amount, price);

If it already exists - it will be replaced with new value, if not - it will be inserted. You don't need to call find. The above 1 line will do the job.

Upvotes: 0

MatthiasB
MatthiasB

Reputation: 1759

Then (with c++11) , you could emplace the element in the map instead of using operator[]

positions.emplace(id, make_shared<PortfolioEntry>(id,amount,price));

How you should handle update depends on the PortfolioEntry class. If it only contains id, amount and price, and constructing is cheap, you can simply override it, and completely drop the update case. If its more complex you have to do your update code anyways.

Upvotes: 0

Related Questions