Reputation: 23789
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
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
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
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